美文网首页iOS面试乔帮主的遗产iOS面试题
iOS Runloop面试题(RunLoop和线程)

iOS Runloop面试题(RunLoop和线程)

作者: 程序员_秃头怪 | 来源:发表于2019-08-03 13:41 被阅读0次

    RunLoop和线程

    • 线程和RunLoop是一一对应的,其映射关系是保存在一个全局的 Dictionary 里
    • 自己创建的线程默认是没有开启RunLoop的

    1、怎么创建一个常驻线程?

    1、为当前线程开启一个RunLoop(第一次调用 [NSRunLoop currentRunLoop]方法时实际是会先去创建一个RunLoop)
    2、向当前RunLoop中添加一个Port/Source等维持RunLoop的事件循环(如果RunLoop的mode中一个item都没有,RunLoop会退出)
    3、启动该RunLoop

      @autoreleasepool {
            
            NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
            
            [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
            
            [runLoop run];
            
        }
    

    2、输出下边代码的执行顺序

    NSLog(@"1");
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"2");
    
        [self performSelector:@selector(test) withObject:nil afterDelay:10];
        
        NSLog(@"3");
    });
    
    NSLog(@"4");
    
    - (void)test
    {
        
        NSLog(@"5");
    }
    

    答案是1423,test方法并不会执行。
    原因是如果是带afterDelay的延时函数,会在内部创建一个 NSTimer,然后添加到当前线程的RunLoop中。也就是如果当前线程没有开启RunLoop,该方法会失效。
    那么我们改成:

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            NSLog(@"2");
            
            [[NSRunLoop currentRunLoop] run];
            
            [self performSelector:@selector(test) withObject:nil afterDelay:10];
      
            NSLog(@"3");
        });
    

    然而test方法依然不执行。
    原因是如果RunLoop的mode中一个item都没有,RunLoop会退出。即在调用RunLoop的run方法后,由于其mode中没有添加任何item去维持RunLoop的时间循环,RunLoop随即还是会退出。
    所以我们自己启动RunLoop,一定要在添加item后

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            NSLog(@"2");
            
            [self performSelector:@selector(test) withObject:nil afterDelay:10];
            
            [[NSRunLoop currentRunLoop] run];
      
            NSLog(@"3");
        });
    

    3、怎样保证子线程数据回来更新UI的时候不打断用户的滑动操作?

    当我们在子请求数据的同时滑动浏览当前页面,如果数据请求成功要切回主线程更新UI,那么就会影响当前正在滑动的体验。
    我们就可以将更新UI事件放在主线程的NSDefaultRunLoopMode上执行即可,这样就会等用户不再滑动页面,主线程RunLoop由UITrackingRunLoopMode切换到NSDefaultRunLoopMode时再去更新UI

    [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO modes:@[NSDefaultRunLoopMode]];
    

    面试题持续整理更新中,需要拿到第一手大厂面试题及答案文档可以添加 iOS进阶学习交流群:551346706 !结实人脉、讨论技术你想要的这里都有!

    相关文章

      网友评论

        本文标题:iOS Runloop面试题(RunLoop和线程)

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