美文网首页
RunLoop入门

RunLoop入门

作者: melody5 | 来源:发表于2018-06-22 16:41 被阅读14次

    我们的项目其实就是一个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]);
    }
    

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

    相关文章

      网友评论

          本文标题:RunLoop入门

          本文链接:https://www.haomeiwen.com/subject/iaxcyftx.html