前言:
之前一直觉得工作上接触不到Runloop,事实上,我们无时无刻都在使用它。
举个例子:
-(void)startConnect {
NSURLConnection *dataConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
}
然后在外部以新启动一个线程方式调用
[NSThread detachNewThreadSelector:@selector(startConnect:) toTarget:self withObject:imageData];
当然,结果是delegate的结果根本没有回调回来!
原因很简单哈,其实就是在在detach的时候会新创建一个线程,而这个线程默认是没有Runloop(当然也没有地方去调用Run)的,又因为NSURLConnectiond的回调默认是需要在当前调用线程的Runloop内部添加CFMultiplexerSource(Source0),但是在添加完之后由于当前线程并没有在地方启动整个Runloop,所以还没等到添加的source手动触发,线程已经退出了。
解决方法:
- 把当前要回调执行schedule到其他已经管理好的线程的Runloop,比如主线程的Runloop 的Default Mode
-(void)startConnect {
NSURLConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:NO];
[dataConnection scheduleInRunLoop:NSRunLoop.mainRunLoop forMode:NSDefaultRunLoopMode];
[dataConnection start];
}
- 如果还是坚持要在当前线程同步回调,可以在添加完source之后,手动启动Runloop
-(void)startConnect {
NSURLConnection *dataConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
[[NSRunLoop currentRunLoop] run];
}
什么是RunLoop?
先看看一下参考资料
Runloop的内部结构:
如果看了Run内部执行结构会发现,如果source/timer/observer都没有的(空)情况下默认runloop会立即退出,典型的例子就是在参考资料内有提到早期版本的AFNetworking会使用新创建一个线程然后在其default mode里添加一个Source1(port),起到占位,防止线程提前退出。
之后会举更多的例子,未完待续~~~~