×

Runloop是怎样进行线程保活

消耗积分:1 | 格式:rar | 大小:0.3 MB | 2017-09-26

分享资料个

  AFN 中的实现

  在旧版本的AFN 中使用了 NSURLConnection 来发起并处理网络连接。

  AFN 的做法是把网络请求的发起和解析都放在同一个子线程中进行,子线程默认不开启 runloop,它会向一个 C语言程序那样在运行完所有代码后退出线程。

  而网络请求是异步的,这导致获取到请求数据时,线程已经退出,代理方法没有机会执行。

  因此,AFN 的做法是使用一个 runloop 来保证线程不死,也就是下面这段被讲烂了的代码:

  + (void)networkRequestThreadEntryPoint:(id)__unused object {

  @autoreleasepool {

  [[NSThread currentThread] setName:@“AFNetworking”];

  NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

  [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];

  [runLoop run];

  }

  }

  稍微结合一下上下文,看看这个方法在哪里被调用:

  + (NSThread *)networkRequestThread {

  static NSThread *_networkRequestThread = nil;

  static dispatch_once_t oncePredicate;

  dispatch_once(&oncePredicate, ^{

  _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];

  [_networkRequestThread start];

  });

  return _networkRequestThread;

  }

  似乎这种写法提供了一种思路:“如果需要在子线程中异步执行操作,可以利用 runloop 进行线程保活”。但准确的来说,AFN 的这种写法并不能实现我们的需求,它只是在 AFN 这个特殊场景下可以工作。

  NSThread 与内存泄漏

  这种写法的第一个问题就是存在内存泄漏。我们构造以下用例,把 AFN 的线程创建放在一个循环里:

  - (void)memoryTest {

  for (int i = 0; i 《 100000; ++i) {

  NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];

  [thread start];

  }

  }

  - (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 run];

  }

  }

  奇怪的事情出现了,尽管是在 ARC 环境下,内存依然不停的上涨。如果我们把 run 方法中和 runloop 相关的代码删除则不会出现上述问题,显然,开启 runloop 导致了内存泄漏,也就是 thread 对象无法释放。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !