Runloop的概念
Runloop的存在主要就是为了线程保活,线程保活是为了线程能够及时的处理事件,不会在其执行完之后立刻释放。Node.js是基于V8引擎工作的,它是单线程操作的,但是Node的执行效率并不低,因为Node有事件轮询和异步回调的机制,而Runloop就像是一个事件轮询。
Runloop与线程
线程刚创建时并没有 RunLoop,不主动获取的话,一直都不会有Runloop。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。只能在一个线程的内部获取其 RunLoop。
RunLoop的使用
1.NSTimer使用时,在ScrollView滑动时失效的问题。
这是因为主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为"Common"属性。DefaultMode 是 App 平时所处的状态,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态。当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个ScrollView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。
有时你需要一个 Timer,在两个 Mode 中都能得到回调,解决办法就是将 Timer 加入到顶层的 RunLoop 的 "commonModeItems" 中。"commonModeItems" 被 RunLoop 自动更新到所有具有"Common"属性的 Mode 里去。
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(setProgress) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:progressTimer forMode:NSRunLoopCommonModes];
2.子线程调用performSelector:afterDelay:失效的问题
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//创建子线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(startThread) object:nil];
[thread start];
}
-(void)startThread{
//此时失效
[self performSelector:@selector(log:) withObject:@"dog" afterDelay:2];
//不会失效
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self log:@"cow"];
});
}
-(void)log:(NSString *)string{
NSLog(@"%@++++",string);
}
这是因为调用 NSObject 的 performSelecter:afterDelay: 后,其内部会创建一个 Timer 并添加到当前线程的 RunLoop 中。所以如果当前线程没有 RunLoop,则这个方法会失效。
3.动态UITableView缓存高度
TableView在缓存高度的时候,我们为了保持界面的流畅性会在页面停止滑动的时候去计算cell的高度。
//获取观察者 观察Runloop的mode状态
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity _) {
if () {
CFRunLoopRemoveObserver(runLoop, observer, runLoopMode); CFRelease(observer); // 注意释放,否则会造成内存泄露
return;
}
//主线程 NSDefaultRunLoopMode 进行计算
[self performSelector:@selector(fd_precacheIndexPathIfNeeded:) onThread:[NSThread mainThread] withObject:indexPath waitUntilDone:NO modes:@[NSDefaultRunLoopMode]];
}
);
爱生活,爱运动,热爱交流,欢迎讨论!