2

我在 iOS 中学到了一条全局规则 -> 永远不要阻塞主线程。但是,有几次我遇到了违反此规则的开源代码片段。

两个这样的例子如下:

以下函数取自 https://github.com/piwik/piwik-sdk-ios/blob/master/PiwikTracker/PiwikTracker.m

- (void)startDispatchTimer {

  // 在主线程运行循环
  __weak typeof(self)weakSelf = self;
  dispatch_async(dispatch_get_main_queue(), ^{

    [weakSelf stopDispatchTimer];

    // 如果调度间隔为 0) {

      // 在计时器上运行
      weakSelf.dispatchTimer = [NSTimer scheduleTimerWithTimeInterval:weakSelf.dispatchInterval
                                                                目标:弱自我
                                                              选择器:@选择器(调度:)
                                                              用户信息:无
                                                               重复:否];

      NSLog(@"Dispatch timer 以间隔 %f 开始", weakSelf.dispatchInterval);

    }

  });

}

在上面的代码中,我一直试图理解为什么计时器对象需要主线程。像这样的事情与 UI 无关,仍然在主线程上完成。

另一个例子是著名的网络库 MKNetworkKit。以下代码在 NSOperation 的 start 方法中。 https://github.com/MugunthKumar/MKNetworkKit/blob/master/MKNetworkKit/MKNetworkOperation.m

dispatch_async(dispatch_get_main_queue(), ^{
      self.connection = [[NSURLConnection alloc] initWithRequest:self.request
                                                        代表:自己
                                                立即开始:否];

      [self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
                                 forMode:NSRunLoopCommonModes];

      [self.connection start];
    });

所以我的问题是为什么人们使用主线程来执行不与 UI 相关的操作,它有什么好处。如果您不坚持它,它可能不会冻结您的应用程序,但为什么要冒险。

4

1 回答 1

2

这两个示例都直接或间接地使用了 NSRunLoop 方法。在这些情况下,您应该从执行目标 NSRunLoop 的线程中调用方法。因此你需要 dispatch_get_main_queue()。

看一下关于 NSRunLoop 的苹果文档 https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/classes/nsrunloop_class/reference/reference.html

警告:NSRunLoop 类通常不被认为是线程安全的,它的方法只能在当前线程的上下文中调用。你永远不应该尝试调用在不同线程中运行的 NSRunLoop 对象的方法,因为这样做可能会导致意外结果。

顺便说一句,NSRunLoop 似乎在 Core Foundation 中使用了 CFRunLoop,而 Core Foundation 是在 Apple 的开源许可下发布的。

http://opensource.apple.com/source/CF/CF-855.17/CFRunLoop.c

看起来 CFRunLoop 是线程安全的(我们可以看到很多 __CFRunLoopLock 和 __CFRunLoopUnlock 组合)。但无论如何你最好遵守文件:)

于 2014-09-11T20:27:26.203 回答