iOS Runloop的理解与使用

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]];
}
);

爱生活,爱运动,热爱交流,欢迎讨论!

你可能感兴趣的:(iOS Runloop的理解与使用)