关于上一篇"RunLoop 学习笔记"存在问题的修复

上一篇中问题, 实现"常驻线程"的方案

上一篇"RunLoop 学习笔记"中是这么介绍常驻线程, 以及对应实现方法的:

即让子线程处于 "不消亡" 的状态, 一直在后台处理某些频发事件 / 等待其他线程发来消息

  • 在子线程监控网络状态
  • 在子线程开启一个定时器
  • 在子线程长期监控其他行为
+ (void)networkRequestThreadEntryPoint:(id)__unused object { 
    @autoreleasepool { 
        [[NSThread currentThread] setName:@"AFNetworking"];        
         NSRunLoop *runLoop = [NSRunLoop currentRunLoop];       
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; [runLoop run]; 
    }
}

摘自 AFNetworking 源代码, AFN这样做的原理在于子线程下默认不开启 RunLoop, 需要手动开启, 而 RunLoop 不断跑圈需要满足以下条件之一 :

  • RunLoop有事件源(输入源), 包含基于端口 (port) 的事件源 / custom 事件源等
  • RunLoop存在定时器

因此, AFN为RunLoop的default模式增加了一个NSMachPort端口(实际上也可以是其他端口),也就相当于为RunLoop添加了事件源, 因此RunLoop可以不断的跑圈, 保证线程的不死状态
顺便提一下, AFN保持一个常驻线程的原因, 第一是因为子线程默认不会开启RunLoop, 它会像一个C语言程序一样运行完所有代码后退出线程, 而网络请求是异步的, 这就可能会出现通过网络请求获取到数据之后, 线程已经退出, 无法执行请求成功/失败的代理方法, 因此AFN开启了一个RunLoop, 保活了线程

这样做存在内存泄漏的问题

经过研究 bestswifter 的文章 深入研究 Runloop 与线程保活 的相关思想与结论, 对以前提出的方案做改进, 并鸣谢该作者

解决方案如下:

- (void)memoryTest {
    for (int i = 0; i < 100000; ++i) {
        NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
        [thread start];
        [self performSelector:@selector(stopThread) onThread:thread withObject:nil waitUntilDone:YES];
    }
}

- (void)stopThread {
    CFRunLoopStop(CFRunLoopGetCurrent());
    NSThread *thread = [NSThread currentThread];
    [thread cancel];
}

- (void)run {
    @autoreleasepool {
        NSLog(@"current thread = %@", [NSThread currentThread]);
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        if (!self.emptyPort) {
            self.emptyPort = [NSMachPort port];
        }
        [runLoop addPort:self.emptyPort forMode:NSDefaultRunLoopMode];
        [runLoop runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
    }
}


文/bestswifter(作者)
原文链接:http://www.jianshu.com/p/10121d699c32
著作权归作者所有,转载请联系作者获得授权,并标注“作者”。

关于 RunLoop 线程保活技术更深层次的理解, 请移步至 bestswifter 的文章 深入研究 Runloop 与线程保活

你可能感兴趣的:(关于上一篇"RunLoop 学习笔记"存在问题的修复)