Runloop模式

2018-05-24  本文已影响0人  抹不掉那伤1

2018-05-24
iOS程序的入口是main函数,在main函数里int a = UIApplicationMain之前的代码可以执行,而在其后面的却不能执行。是因为UIApplicationMain里面开启了一个死循环(Runloop 循环)。

意义

- (void)viewDidLoad {
    [super viewDidLoad];
    NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(otherMethod) userInfo:nil repeats:YES];
}
-(void)otherMethod{
    NSLog(@"OtherMethod --- %@",[NSThread currentThread]);
}

以上的otherMethod方法并不会执行,timer被释放了,通过在viewDidLoad后面添加下面的代码可以证明。

    __weak typeof(timer) aaaaa = timer;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (aaaaa == nil) {
            NSLog(@"释放了");
        }
    });

那么应该如何解决呢?我们将timer添加到Runloop当中添加以下代码

  [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

运行后otherMethod开始执行了,timer也不释放了。
上面说Runloop会监听UI事件,如果在app里添加一给UIScrollView并在运行后滚动它,会发现otherMethod方法停止了调用,停止滚动后就恢复了。这是为什么呢?

Runloop监听所有事件是分模式的,我的理解就是Runloop将处理的事件分类,当Runloop处在一个模式下就会处理对应的类别的事件。

前面将timer添加到Runloop的时候传的参数是NSDefaultRunLoopMode就相当于将timer产生的事件标记为Runloop在默认模式下才会监听的事件,而在滑动UIScrollView时Runloop的UI模式下的Source会产生事件,又因为UI模式的优先级高,Runloop会切换到UI模式(即:默认模式下的timer和UI模式下的Source同时产生事件时,会监听后者),这时otherMethod方法就不会执行了。

NSDefaultRunLoopMode改为UITrackingRunLoopMode,触摸并滑动UIScrollView后可以发现otherMethod方法开始执行了,松开手后又停止执行了,是因为UI模式只会被触摸事件所触发

为了让拖拽与否都能处理Timer事件可以这样

[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

将Timer分别添加到两个模式中去,但是苹果有更好的办法,向下面的那样。

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

NSRunLoopCommonModes占位模式,相当于NSDefaultRunLoopModeUITrackingRunLoopMode的两个模式的组合。

上一篇下一篇

猜你喜欢

热点阅读