001两种队列形式:主队列,自定义队列。添加到主队列的NSOperation会放在主线程中执行,放在自定义队列的NSOperation,默认放在子线程并发执行。
002 向NSOperationQueue
添加操作
代码实例:
- (void)testAddFunction{
NSOperationQueue *mainQueue = [NSOperationQueue currentQueue];
NSOperationQueue *theQueue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op1");
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op2");
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op3");
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op4");
}];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op5");
}];
[mainQueue addOperation:op1];
[mainQueue addOperations:@[op2,op4,op3,op5] waitUntilFinished:NO];
[mainQueue addOperationWithBlock:^{
NSLog(@"addOperationWithBlock");
}];
}
2020-11-01 10:30:59.576579+0800 GCDPropertyQueue[5216:477013] op1
2020-11-01 10:30:59.577015+0800 GCDPropertyQueue[5216:477013] op2
2020-11-01 10:30:59.579641+0800 GCDPropertyQueue[5216:477013] op4
2020-11-01 10:30:59.580128+0800 GCDPropertyQueue[5216:477013] op3
2020-11-01 10:30:59.580325+0800 GCDPropertyQueue[5216:477013] op5
2020-11-01 10:30:59.580565+0800 GCDPropertyQueue[5216:477013] addOperationWithBlock
003 如果NSOperationQueue添加了之前添加的操作那就会闪退
[mainQueue addOperation:op1];
[mainQueue addOperation:op1];
[mainQueue addOperation:op1];
[mainQueue addOperations:@[op2,op4,op3,op5,op1] waitUntilFinished:NO];
上源码:
- (void) addOperation: (NSOperation *)op
{
if (op == nil || NO == [op isKindOfClass: [NSOperation class]])
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] object is not an NSOperation",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
[internal->lock lock];
if (NSNotFound == [internal->operations indexOfObjectIdenticalTo: op]
&& NO == [op isFinished])
{
[op addObserver: self
forKeyPath: @"isReady"
options: NSKeyValueObservingOptionNew
context: isReadyCtxt];
[self willChangeValueForKey: @"operations"];
[self willChangeValueForKey: @"operationCount"];
[internal->operations addObject: op];
[self didChangeValueForKey: @"operationCount"];
[self didChangeValueForKey: @"operations"];
if (YES == [op isReady])
{
[self observeValueForKeyPath: @"isReady"
ofObject: op
change: nil
context: isReadyCtxt];
}
}
[internal->lock unlock];
}
- (void) addOperations: (NSArray *)ops
waitUntilFinished: (BOOL)shouldWait
{
NSUInteger total;
NSUInteger index;
if (ops == nil || NO == [ops isKindOfClass: [NSArray class]])
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] object is not an NSArray",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
}
total = [ops count];
if (total > 0)
{
BOOL invalidArg = NO;
NSUInteger toAdd = total;
GS_BEGINITEMBUF(buf, total, id)
[ops getObjects: buf];
for (index = 0; index < total; index++)
{
NSOperation *op = buf[index];
if (NO == [op isKindOfClass: [NSOperation class]])
{
invalidArg = YES;
toAdd = 0;
break;
}
if (YES == [op isFinished])
{
buf[index] = nil;
toAdd--;
}
}
if (toAdd > 0)
{
[internal->lock lock];
[self willChangeValueForKey: @"operationCount"];
[self willChangeValueForKey: @"operations"];
for (index = 0; index < total; index++)
{
NSOperation *op = buf[index];
if (op == nil)
{
continue; // Not added
}
if (NSNotFound
!= [internal->operations indexOfObjectIdenticalTo: op])
{
buf[index] = nil; // Not added
toAdd--;
continue;
}
[op addObserver: self
forKeyPath: @"isReady"
options: NSKeyValueObservingOptionNew
context: isReadyCtxt];
[internal->operations addObject: op];
if (NO == [op isReady])
{
buf[index] = nil; // Not yet ready
}
}
[self didChangeValueForKey: @"operationCount"];
[self didChangeValueForKey: @"operations"];
for (index = 0; index < total; index++)
{
NSOperation *op = buf[index];
if (op != nil)
{
[self observeValueForKeyPath: @"isReady"
ofObject: op
change: nil
context: isReadyCtxt];
}
}
[internal->lock unlock];
}
GS_ENDITEMBUF()
if (YES == invalidArg)
{
[NSException raise: NSInvalidArgumentException
format: @"[%@-%@] object at index %"PRIuPTR" is not an NSOperation",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
index];
}
}
if (YES == shouldWait)
{
[self waitUntilAllOperationsAreFinished];
}
}
NSOperationQueue *mainQueue = [NSOperationQueue currentQueue];
[mainQueue addOperations:@[op2,op4,op3,op5] waitUntilFinished:YES];
主线程将会阻塞,直到队列中的所有任务完成。
- (void) waitUntilAllOperationsAreFinished
{
NSOperation *op;
[internal->lock lock];
while ((op = [internal->operations lastObject]) != nil)
{
[op retain];
[internal->lock unlock];
[op waitUntilFinished];
[op release];
[internal->lock lock];
}
[internal->lock unlock];
}