RunLoop入门

2018-06-22  本文已影响14人  melody5

我们的项目其实就是一个RunLoop,比如main函数的UIApplicationMain就是一个死循环函数,它在不停的询问是否有事件发生,比如我在main函数里这样写:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        NSLog(@"%@",[NSThread currentThread]);
        //UIApplicationMain  死循环 -- Runloop循环
        int a = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        NSLog(@"来了没");
        return a;
    }
}
2018-06-21 17:10:56.622877+0800 001--Runloop1[752:290434] <NSThread: 0x1d0075280>{number = 1, name = main}

最后我只得到了第一次打印,证明程序在UIApplicationMain函数进入了死循环,所以没有走到我的第二次打印

1、RunLoop的作用

  1. 保住当前线程的生命
  2. 监听事件:触摸,网络,时钟

2、RunLoop的几种运行模式

    NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
    
    //timer添加到Runloop中!!
    //NSDefaultRunLoopMode    默认模式,如果UI有操作时,runloop会暂停
    //UITrackingRunLoopMode   UI模式,当UI上有滑动等操作时才会运行,否则暂停
    //NSRunLoopCommonModes    占位模式!!UI&&默认!,在前两种模式下都会运行

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
- (void)timerMethod {
    
    NSLog(@"%@--跑起来!!",[NSThread currentThread]);
}

通过打印就可以看出他们的区别,自己验证一下吧,比如放一个scrollView,比较滑动和不滑动时几种模式的不同。

3、用RunLoop保住线程的生命

如果不想RunLoop受到UI操作的影响,我们可以把他放到子线程里去执行

    NSThread * thread = [[NSThread alloc] initWithBlock:^{
        NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0001]];
        NSLog(@"走起");
        
    }];
    
    [thread start];

但是这时候发现,只有“走起”被打印了,timer的timerMethod并没有执行,这是因为thread里的代码执行完之后thread就销毁了,我们自定义一个继承自NSThread的类,然后实现它的dealloc方法,可以发现它被销毁了

-(void)dealloc
{
    NSLog(@"线程挂了");
}
2018-06-21 18:03:53.979368+0800 001--Runloop1[767:305273] 走起
2018-06-21 18:03:53.979485+0800 001--Runloop1[767:305273] 线程挂了

到这个你可能会说,让控制器强引用它不就完了吗?
但是并不行,因为这样OC的对象被留住了,但是底层的线程还是被释放了,那怎么才能保住当前线程的生命呢?

答案是让线程有执行不完的任务!!!
    NSThread * thread = [[NSThread alloc] initWithBlock:^{
        NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        while (true) {
            [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0001]];
        }
        NSLog(@"走起");
        
    }];
    
    [thread start];

这时候发现,timerMethod方法被循环的调用起来了。我们把while的条件换成变量以后,运行过程把true变成f'alse,会发现RunLoop会停止,线程会销毁。

4、线程间的通讯

    NSThread * thread = [[NSThread alloc] initWithBlock:^{

        NSLog(@"-----%@",[NSThread currentThread]);
        [[NSRunLoop currentRunLoop] run];
    }];

    [thread start];

    [self performSelector:@selector(subThreadMethod) onThread:thread withObject:nil waitUntilDone:NO];
-(void)subThreadMethod{
    NSLog(@"subThreadMethod --- %@",[NSThread currentThread]);
}

在主线程给子线程添加执行代码。

上一篇 下一篇

猜你喜欢

热点阅读