NSOperation和NSOperationQueue验证笔记
- 如果想了解NSOperation和NSOperationQueue的基本概念或者一些理解,请先阅读iOS 并发编程之 Operation Queues
准备工作
// 自定义一个类继承NSBlockOperation,
// 重写相关的方法,观察声明周期@interface LKBlockOperation : NSBlockOperation
@end@implementation LKBlockOperation- (void)dealloc
{
NSLog(@"LKBlockOperation dealloc");
}- (void)start
{
NSLog(@"Operation before execute super start");
[super start];
NSLog(@"Operation after execute super start");
}- (void)main
{
NSLog(@"Operation before execute super main");
[super main];
NSLog(@"Operation after execute super main");
}
@end
操作执行过程
// 通过下面的代码和打印可知:
// 把Operation加入到Queue中并不是立马就执行
// 执行过程: start -> main -> CompletionBlock -> dealloc- (void)testExecuteOperation
{
LKBlockOperation *operation = [[LKBlockOperation alloc] init];
[operation addExecutionBlock:^{NSLog(@"before execute operation");
NSInteger i = 0;
while (i < 3) {
NSLog(@"%@_%zd", [NSThread currentThread], ++i);
}NSLog(@"after execute operation");
}];
[operation setCompletionBlock:^{
NSLog(@"completion");
}];
NSLog(@"before queue Add Operation");
[_queue addOperation:operation];
NSLog(@"after queue Add Operation");
}/*
2018-03-01 13:42:57.494851+0800 OperationQueues[3797:129659] before queue Add Operation
2018-03-01 13:42:57.495266+0800 OperationQueues[3797:129659] after queue Add Operation
2018-03-01 13:42:57.495350+0800 OperationQueues[3797:129708] Operation before execute super start
2018-03-01 13:42:57.495594+0800 OperationQueues[3797:129708] Operation before execute super main
2018-03-01 13:42:57.495940+0800 OperationQueues[3797:129708] before execute operation
2018-03-01 13:42:57.496402+0800 OperationQueues[3797:129708] {number = 3, name = (null)}_1
2018-03-01 13:42:57.497014+0800 OperationQueues[3797:129708] {number = 3, name = (null)}_2
2018-03-01 13:42:57.497155+0800 OperationQueues[3797:129708] {number = 3, name = (null)}_3
2018-03-01 13:42:57.497389+0800 OperationQueues[3797:129708] after execute operation
2018-03-01 13:42:57.497501+0800 OperationQueues[3797:129708] Operation after execute super main
2018-03-01 13:42:57.497645+0800 OperationQueues[3797:129708] Operation after execute super start
2018-03-01 13:42:57.497648+0800 OperationQueues[3797:129700] completion
2018-03-01 13:42:57.556400+0800 OperationQueues[3797:129700] LKBlockOperation dealloc
*/
如果任务还没加入到队列中就取消
// 通过下面的代码和打印可知:
// 如果任务在没有加入到队列之前就取消,还是会调用start和CompletionBlock。但是main函数是不会执行了。
// 还可以看到在start方法执行之前,isCancel已经为YES,
// 说明调用cancel方法之后,isCacel就会设置为YES,然后在根据是否取消来决定是否调用main方法- (void)testCancelBeforeAddToOperation
{
LKBlockOperation *operation = [[LKBlockOperation alloc] init];
[operation addExecutionBlock:^{
NSInteger i = 0;
while (1) {
NSLog(@"%@_%zd", [NSThread currentThread], i ++);
}
}];
[operation setCompletionBlock:^{
NSLog(@"completion");
}];
[operation cancel];
NSLog(@"before queue Add Operation");
[_queue addOperation:operation];
NSLog(@"after queue Add Operation");
}/*
2018-03-01 13:59:02.415212+0800 OperationQueues[4099:142821] before queue Add Operation
2018-03-01 13:59:02.415394+0800 OperationQueues[4099:142821] after queue Add Operation
2018-03-01 13:59:02.415428+0800 OperationQueues[4099:142863] self.cancel = 1
2018-03-01 13:59:02.415526+0800 OperationQueues[4099:142863] Operation before execute super start
2018-03-01 13:59:02.415739+0800 OperationQueues[4099:142866] completion
2018-03-01 13:59:02.415739+0800 OperationQueues[4099:142863] Operation after execute super start
2018-03-01 13:59:02.415907+0800 OperationQueues[4099:142863] LKBlockOperation dealloc
*/
任务的中途取消
// 通过下面的代码和打印可知:
// 通过上面的测试我们知道当调用Cancel方法之后,isCancelled就会设置为YES,
// 所以我们应该在每一次执行耗时操作或者是循环都应该判断下isCancelled,这也是苹果推荐的。
// 我把if(weakOperation.isCancelled) {break;
}去掉之后,这个任务是不能正常取消的,就算调用了cancel方法。因为这个任务并没有结束的标志(return)- (void)testCancelOperationWhenExecuting
{
NSBlockOperation *operation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakOperation = operation;
[operation addExecutionBlock:^{NSLog(@"before execute operation");
NSInteger i = 0;
while (1) {NSLog(@"%@_%zd", [NSThread currentThread], i ++);
if(weakOperation.isCancelled) {
break;
}if(i == 3) {
[weakOperation cancel];
}
}NSLog(@"after execute operation");
}];
[operation setCompletionBlock:^{
NSLog(@"completion");
}];
NSLog(@"before queue Add Operation");
[_queue addOperation:operation];
NSLog(@"after queue Add Operation");
}/*
2018-03-01 14:08:52.408137+0800 OperationQueues[4342:152805] before queue Add Operation
2018-03-01 14:08:52.408288+0800 OperationQueues[4342:152805] after queue Add Operation
2018-03-01 14:08:52.408332+0800 OperationQueues[4342:152842] before execute operation
2018-03-01 14:08:52.408608+0800 OperationQueues[4342:152842] {number = 3, name = (null)}_1
2018-03-01 14:08:52.408840+0800 OperationQueues[4342:152842] {number = 3, name = (null)}_2
2018-03-01 14:08:52.408988+0800 OperationQueues[4342:152842] {number = 3, name = (null)}_3
2018-03-01 14:08:52.409110+0800 OperationQueues[4342:152842] {number = 3, name = (null)}_4
2018-03-01 14:08:52.409197+0800 OperationQueues[4342:152842] after execute operation
2018-03-01 14:08:52.409339+0800 OperationQueues[4342:152852] completion
*/
NSOperationQueue
准备工作
- (NSBlockOperation *)createOperationRepeatCount:(NSInteger)count operationName:(NSString *)operationName
{
NSBlockOperation *operation = [[NSBlockOperation alloc] init];
operation.name = operationName;
__weak NSBlockOperation *weakOperation = operation;
[operation addExecutionBlock:^{NSLog(@"%@ before execute operation", weakOperation.name);
NSInteger i = 0;
while (i < count) {
NSLog(@"%@-%zd", weakOperation.name, ++i);
if(weakOperation.isCancelled) {
break;
}
}NSLog(@"%@ after execute operation", weakOperation.name);
}];
return operation;
}
测试Queue的Cancel
// 通过下面的代码和打印可知:
// 调用cancelAllOperations和调用Operation的cancel一致。相当于里面遍历Operation。然后调用cancel- (void)testQueueCancel
{
NSBlockOperation *operation0 = [self createOperationRepeatCount:NSIntegerMax operationName:@"operation0"];
NSBlockOperation *operation1 = [self createOperationRepeatCount:NSIntegerMax operationName:@"operation1"];
NSBlockOperation *operation2 = [self createOperationRepeatCount:NSIntegerMax operationName:@"operation2"];
[_queue addOperation:operation0];
[_queue addOperation:operation1];
[_queue addOperation:operation2];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[_queue cancelAllOperations];
});
}/*
2018-03-01 15:26:50.856400+0800 OperationQueues[6275:233403] operation2 before execute operation
2018-03-01 15:26:50.856403+0800 OperationQueues[6275:233402] operation0 before execute operation
2018-03-01 15:26:50.856412+0800 OperationQueues[6275:233400] operation1 before execute operation
2018-03-01 15:26:50.856559+0800 OperationQueues[6275:233403] operation2-1
2018-03-01 15:26:50.856570+0800 OperationQueues[6275:233402] operation0-1
2018-03-01 15:26:50.856571+0800 OperationQueues[6275:233400] operation1-1
2018-03-01 15:26:50.856706+0800 OperationQueues[6275:233403] operation2-2
2018-03-01 15:26:50.856773+0800 OperationQueues[6275:233402] operation0-2
2018-03-01 15:26:50.856777+0800 OperationQueues[6275:233400] operation1-2
2018-03-01 15:26:50.856795+0800 OperationQueues[6275:233403] operation2-3
2018-03-01 15:26:50.856959+0800 OperationQueues[6275:233402] operation0-3
2018-03-01 15:26:50.857556+0800 OperationQueues[6275:233400] operation1-3
2018-03-01 15:26:50.857759+0800 OperationQueues[6275:233403] operation2-4
2018-03-01 15:26:50.858005+0800 OperationQueues[6275:233402] operation0-4
2018-03-01 15:26:50.858166+0800 OperationQueues[6275:233400] operation1-4
2018-03-01 15:26:50.858610+0800 OperationQueues[6275:233403] operation2-5
2018-03-01 15:26:50.858802+0800 OperationQueues[6275:233402] operation0-5
2018-03-01 15:26:50.858977+0800 OperationQueues[6275:233400] operation1-5
2018-03-01 15:26:50.859305+0800 OperationQueues[6275:233403] operation2-6
2018-03-01 15:26:50.920413+0800 OperationQueues[6275:233403] operation2 after execute operation
2018-03-01 15:26:50.920420+0800 OperationQueues[6275:233402] operation0 after execute operation
2018-03-01 15:26:50.920427+0800 OperationQueues[6275:233400] operation1 after execute operation
*/
测试Queue的Suspended
// 通过下面的代码和打印可知:
// 先把setMaxConcurrentOperationCount设置为1, 让操作一个一个的执行
// 当operation0执行完的时候,就设置暂停,但是operation1还是会执行,
// 但是operation2是不会执行,需要等待取消暂停,operation2才会继续执行
// 可以把Queue当成水管,Suspended属性当成水龙头,当水龙头关了, 后面的水就出不来(也就是不执行)- (void)testQueueSuspended
{
[_queue setMaxConcurrentOperationCount:1];
NSBlockOperation *operation0 = [self createOperationRepeatCount:3 operationName:@"operation0"];
NSBlockOperation *operation1 = [self createOperationRepeatCount:3 operationName:@"operation1"];
NSBlockOperation *operation2 = [self createOperationRepeatCount:3 operationName:@"operation2"];
__weak NSOperationQueue *weakQueue = _queue;
[operation0 setCompletionBlock:^{NSLog(@"queue setSuspended YES");
[weakQueue setSuspended:YES];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"after 1 second queue setSuspended NO");
[weakQueue setSuspended:NO];
});
}];
[_queue addOperation:operation0];
[_queue addOperation:operation1];
[_queue addOperation:operation2];
}/*
2018-03-01 15:28:45.414606+0800 OperationQueues[6346:235874] operation0 before execute operation
2018-03-01 15:28:45.414772+0800 OperationQueues[6346:235874] operation0-1
2018-03-01 15:28:45.414883+0800 OperationQueues[6346:235874] operation0-2
2018-03-01 15:28:45.414992+0800 OperationQueues[6346:235874] operation0-3
2018-03-01 15:28:45.415142+0800 OperationQueues[6346:235874] operation0 after execute operation
2018-03-01 15:28:45.415287+0800 OperationQueues[6346:235875] queue setSuspended YES
2018-03-01 15:28:45.415313+0800 OperationQueues[6346:235872] operation1 before execute operation
2018-03-01 15:28:45.415432+0800 OperationQueues[6346:235872] operation1-1
2018-03-01 15:28:45.415526+0800 OperationQueues[6346:235872] operation1-2
2018-03-01 15:28:45.415613+0800 OperationQueues[6346:235872] operation1-3
2018-03-01 15:28:45.415714+0800 OperationQueues[6346:235872] operation1 after execute operation
2018-03-01 15:28:46.508915+0800 OperationQueues[6346:235837] after 1 second queue setSuspended NO
2018-03-01 15:28:46.509152+0800 OperationQueues[6346:235872] operation2 before execute operation
2018-03-01 15:28:46.509272+0800 OperationQueues[6346:235872] operation2-1
2018-03-01 15:28:46.509368+0800 OperationQueues[6346:235872] operation2-2
2018-03-01 15:28:46.509455+0800 OperationQueues[6346:235872] operation2-3
2018-03-01 15:28:46.509564+0800 OperationQueues[6346:235872] operation2 after execute operation
*/
添加顺序对操作执行顺序的影响
// 通过下面的代码和打印可知:
// 任务是按照FIFO的方式进行的, 也就是从先执行operation0 -> operation1 -> operation2
// 但是并不意味着operation0里面的任务代码会先执行// 举个例子:
// 假如往queue中加入10个operation, 分别是operation0~operation9,依次顺序到队列
// 设置OperationCoun = 2, 这个时候先执行operation0和operation1
// 等opertaion0或者operation1其中一个执行完,接下来的一个执行的就是operation3,等下一个任务执行完,接下来执行的就是operation4- (void)testQueueConcurrentOperationCount
{
[_queue setMaxConcurrentOperationCount:2];
NSBlockOperation *operation0 = [self createOperationRepeatCount:2 operationName:@"operation0"];
NSBlockOperation *operation1 = [self createOperationRepeatCount:2 operationName:@"operation1"];
NSBlockOperation *operation2 = [self createOperationRepeatCount:2 operationName:@"operation2"];
[_queue addOperation:operation0];
[_queue addOperation:operation1];
[_queue addOperation:operation2];
}/*
maxConcurrentOperationCount = 1 的情况2018-03-01 15:31:58.001022+0800 OperationQueues[6485:240841] operation0 before execute operation
2018-03-01 15:31:58.001177+0800 OperationQueues[6485:240841] operation0-1
2018-03-01 15:31:58.001363+0800 OperationQueues[6485:240841] operation0-2
2018-03-01 15:31:58.001473+0800 OperationQueues[6485:240841] operation0 after execute operation
2018-03-01 15:31:58.001622+0800 OperationQueues[6485:240830] operation1 before execute operation
2018-03-01 15:31:58.002013+0800 OperationQueues[6485:240830] operation1-1
2018-03-01 15:31:58.002187+0800 OperationQueues[6485:240830] operation1-2
2018-03-01 15:31:58.002287+0800 OperationQueues[6485:240830] operation1 after execute operation
2018-03-01 15:31:58.002428+0800 OperationQueues[6485:240829] operation2 before execute operation
2018-03-01 15:31:58.002528+0800 OperationQueues[6485:240829] operation2-1
2018-03-01 15:31:58.002623+0800 OperationQueues[6485:240829] operation2-2
2018-03-01 15:31:58.002709+0800 OperationQueues[6485:240829] operation2 after execute operation
*//*
maxConcurrentOperationCount = 2 的情况2018-03-01 15:33:10.568711+0800 OperationQueues[6522:242194] operation1 before execute operation
2018-03-01 15:33:10.568722+0800 OperationQueues[6522:242197] operation0 before execute operation
2018-03-01 15:33:10.568877+0800 OperationQueues[6522:242194] operation1-1
2018-03-01 15:33:10.568882+0800 OperationQueues[6522:242197] operation0-1
2018-03-01 15:33:10.568990+0800 OperationQueues[6522:242194] operation1-2
2018-03-01 15:33:10.568997+0800 OperationQueues[6522:242197] operation0-2
2018-03-01 15:33:10.569093+0800 OperationQueues[6522:242194] operation1 after execute operation
2018-03-01 15:33:10.569105+0800 OperationQueues[6522:242197] operation0 after execute operation
2018-03-01 15:33:10.569271+0800 OperationQueues[6522:242237] operation2 before execute operation
2018-03-01 15:33:10.569530+0800 OperationQueues[6522:242237] operation2-1
2018-03-01 15:33:10.569750+0800 OperationQueues[6522:242237] operation2-2
2018-03-01 15:33:10.569982+0800 OperationQueues[6522:242237] operation2 after execute operation
*/
Operation间的Dependency对操作执行顺序的影响
// 注意: 添加依赖需要在加入到队列之前,并且不要相互依赖,否则就造成死锁// 通过下面的代码和打印可知:
// 添加了依赖的操作打破了上面(添加顺序对操作执行的影响)的规律,但是没有添加依赖的操作还是遵守的- (void)testQueueOperationDependency
{
[_queue setMaxConcurrentOperationCount:2];
NSBlockOperation *operation0 = [self createOperationRepeatCount:2 operationName:@"operation0"];
NSBlockOperation *operation1 = [self createOperationRepeatCount:2 operationName:@"operation1"];
NSBlockOperation *operation2 = [self createOperationRepeatCount:2 operationName:@"operation2"];
NSBlockOperation *operation3 = [self createOperationRepeatCount:2 operationName:@"operation3"];
NSBlockOperation *operation4 = [self createOperationRepeatCount:2 operationName:@"operation4"];
[operation0 addDependency:operation1];
[_queue addOperation:operation0];
[_queue addOperation:operation1];
[_queue addOperation:operation2];
[_queue addOperation:operation3];
[_queue addOperation:operation4];
}/*
2018-03-01 16:02:47.435604+0800 OperationQueues[7178:269608] operation2 before execute operation
2018-03-01 16:02:47.435608+0800 OperationQueues[7178:269616] operation1 before execute operation
2018-03-01 16:02:47.435778+0800 OperationQueues[7178:269608] operation2-1
2018-03-01 16:02:47.435782+0800 OperationQueues[7178:269616] operation1-1
2018-03-01 16:02:47.435881+0800 OperationQueues[7178:269608] operation2-2
2018-03-01 16:02:47.435918+0800 OperationQueues[7178:269616] operation1-2
2018-03-01 16:02:47.435997+0800 OperationQueues[7178:269608] operation2 after execute operation
2018-03-01 16:02:47.436063+0800 OperationQueues[7178:269616] operation1 after execute operation
2018-03-01 16:02:47.436164+0800 OperationQueues[7178:269606] operation3 before execute operation
2018-03-01 16:02:47.436196+0800 OperationQueues[7178:269608] operation0 before execute operation
2018-03-01 16:02:47.436314+0800 OperationQueues[7178:269606] operation3-1
2018-03-01 16:02:47.436816+0800 OperationQueues[7178:269608] operation0-1
2018-03-01 16:02:47.437014+0800 OperationQueues[7178:269606] operation3-2
2018-03-01 16:02:47.437182+0800 OperationQueues[7178:269608] operation0-2
2018-03-01 16:02:47.437341+0800 OperationQueues[7178:269606] operation3 after execute operation
2018-03-01 16:02:47.437520+0800 OperationQueues[7178:269608] operation0 after execute operation
2018-03-01 16:02:47.480951+0800 OperationQueues[7178:269606] operation4 before execute operation
2018-03-01 16:02:47.481082+0800 OperationQueues[7178:269606] operation4-1
2018-03-01 16:02:47.481191+0800 OperationQueues[7178:269606] operation4-2
2018-03-01 16:02:47.481290+0800 OperationQueues[7178:269606] operation4 after execute operation
*/
Operation间的Dependency
// 注意: 添加依赖需要在加入到队列之前,并且不要相互依赖,否则就造成死锁// 通过下面的代码和打印可知:
// 就算设置MaxConcurrentOperationCount = 2,操作还是一个一个的执行
// 添加了依赖,顺序页修改了,请参照上面(Operation间的Dependency对操作执行顺序的影响)- (void)testQueueOperationDependency
{
[_queue setMaxConcurrentOperationCount:2];
NSBlockOperation *operation0 = [self createOperationRepeatCount:2 operationName:@"operation0"];
NSBlockOperation *operation1 = [self createOperationRepeatCount:2 operationName:@"operation1"];
NSBlockOperation *operation2 = [self createOperationRepeatCount:2 operationName:@"operation2"];
[operation1 addDependency:operation2];
[operation0 addDependency:operation1];
[_queue addOperation:operation0];
[_queue addOperation:operation1];
[_queue addOperation:operation2];
}/*
2018-03-01 15:56:03.770607+0800 OperationQueues[7053:264284] operation2 before execute operation
2018-03-01 15:56:03.770749+0800 OperationQueues[7053:264284] operation2-1
2018-03-01 15:56:03.770840+0800 OperationQueues[7053:264284] operation2-2
2018-03-01 15:56:03.770960+0800 OperationQueues[7053:264284] operation2 after execute operation
2018-03-01 15:56:03.771122+0800 OperationQueues[7053:264295] operation1 before execute operation
2018-03-01 15:56:03.771228+0800 OperationQueues[7053:264295] operation1-1
2018-03-01 15:56:03.771336+0800 OperationQueues[7053:264295] operation1-2
2018-03-01 15:56:03.771458+0800 OperationQueues[7053:264295] operation1 after execute operation
2018-03-01 15:56:03.771578+0800 OperationQueues[7053:264295] operation0 before execute operation
2018-03-01 15:56:03.771681+0800 OperationQueues[7053:264295] operation0-1
2018-03-01 15:56:03.771785+0800 OperationQueues[7053:264295] operation0-2
2018-03-01 15:56:03.771880+0800 OperationQueues[7053:264295] operation0 after execute operation
*/
补充
- queuePriority属性只是在运行的时候,只是会资源的分配,并不会影响到上面所说的顺序
推荐阅读
- 急于表达——往往欲速则不达
- 第三节|第三节 快乐和幸福(12)
- 20170612时间和注意力开销记录
- 2.6|2.6 Photoshop操作步骤的撤消和重做 [Ps教程]
- 对称加密和非对称加密的区别
- 眼光要放高远
- 樱花雨
- 前任
- 2020-04-07vue中Axios的封装和API接口的管理
- 烦恼和幸福