平时工作中经常会遇到这种需求: 开启线程A,等待A中的操作全部完成后,才执行下面的操作。
解决办法:
NSRunLoop
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"sleep");
[NSThread sleepForTimeInterval:3];
NSLog(@"end sleep");
isdone = YES;
});
while(!isdone){
[[NSRunLoop currentRunLoop] NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
NSLog(@"3333333");
执行结果:
2017-04-28 17:02:49.678 newTest[4692:2108632] sleep
2017-04-28 17:02:52.685 newTest[4692:2108632] end sleep
2017-04-28 17:02:52.685 newTest[4692:2108575] 3333333
在做这个示例的时候,遇到一个问题: 我是在ViewDidLoad()方法中去执行上面这段代码的,运行的时候回先打印‘sleep’,然后等3S打印'end sleep', 但是 '3333333' 有时候会等很长时间才打印出来。 将 NSDefaultRunLoopMode 改成 NSRunLoopCommonModes 就可以立即打印出来。 有可能当前RunLoopMode 切换成了 NSRunLoopCommonModes,导致结果打印不出来; 通过调用 NSLog(@"%@",[NSRunLoop currentRunLoop]); 输出当前RunLoopMode,发现当前RunLoopMode确实是NSRunLoopCommonModes。
common modes = <CFBasicHash 0x145603140 [0x1a154c150]>{type = mutable set, count = 2,
entries =>
0 : <CFString 0x19d3a16e0 [0x1a154c150]>{contents = "UITrackingRunLoopMode"}
2 : <CFString 0x19cb69020 [0x1a154c150]>{contents = "kCFRunLoopDefaultMode"}
}
在子线程中执行这段代码,可以正常输出结果
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"sleep");
[NSThread sleepForTimeInterval:3];
NSLog(@"end sleep");
isdone = YES;
});
NSLog(@"%@",[NSRunLoop currentRunLoop]);
while(!isdone){
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
NSLog(@"3333333");
});
子线程中的RunLoopMode是 NSDefaultRunLoopMode
common modes = <CFBasicHash 0x126e770d0 [0x1a154c150]>{type = mutable set, count = 1,
entries =>
2 : <CFString 0x19cb69020 [0x1a154c150]>{contents = "kCFRunLoopDefaultMode"}
}
关于线程和RunLoop的关系,传送门
dispatch信号量
//初始化信号量为0
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"sleep");
[NSThread sleepForTimeInterval:3];
NSLog(@"end sleep");
//信号量+1
dispatch_semaphore_signal(sema);
});
//信号量-1,如果信号量 < 0,继续等待;信号量 >=0 ,执行下面的操作
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
NSLog(@"3333333");
执行结果:
2017-04-28 17:02:49.678 newTest[4692:2108632] sleep
2017-04-28 17:02:52.685 newTest[4692:2108632] end sleep
2017-04-28 17:02:52.685 newTest[4692:2108575] 3333333
NSOperation
//NSOperationQueue + NSBlockOperation
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *ope = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:3];
NSLog(@"sleep");
[NSThread sleepForTimeInterval:3];
NSLog(@"end sleep");
}];
[queue addOperations:@[invo] waitUntilFinished:YES];
NSLog(@"3333333");
输出结果:
2017-04-28 16:36:54.247 newTest[4663:2100420] sleep
2017-04-28 16:36:57.249 newTest[4663:2100420] end sleep
2017-04-28 16:36:57.250 newTest[4663:2100375] 3333333
//NSOperationQueue + NSInvocationOperation
使用NSInvocationOperation的好处是,可以获取selector的执行结果;
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *ope = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(showmsg) object:nil];
[queue addOperations:@[ope] waitUntilFinished:YES];
NSLog(@"%@", ope.result);
NSLog(@"3333333");
}
-(NSNumber *)showmsg
{
NSLog(@"sleep");
[NSThread sleepForTimeInterval:3];
NSLog(@"end sleep");
return @100;
}
输出结果:
2017-04-28 16:38:39.380 newTest[4667:2100951] sleep
2017-04-28 16:38:42.383 newTest[4667:2100951] end sleep
2017-04-28 16:38:42.384 newTest[4667:2100926] 100
2017-04-28 16:38:42.384 newTest[4667:2100926] 3333333