在主线程上调用 - [NSRunLoop runMode:beforeDate:]会导致排队的NSOperations在主线程上运行

时间:2012-03-06 19:35:09

标签: ios nsoperation nsoperationqueue nsrunloop

今天我遇到了一个问题,我的应用程序无法及时启动。事实证明我正在使用的一些第三方代码试图使用以下技巧获取用户代理字符串:

-(NSString*)userAgentString
{
    webView = [[UIWebView alloc] init];
    webView.delegate = self;
    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"www.google.com"]]];

    // Wait for the web view to load our bogus request and give us the secret user agent.
    while (self.userAgent == nil) 
    {
        // This executes another run loop. 
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }

    return self.userAgent;
}

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    self.userAgent = [request valueForHTTPHeaderField:@"User-Agent"];

    // Return no, we don't care about executing an actual request.
    return NO;
}

(来自http://blog.sallarp.com/iphone-ipad-get-user-agent-for-uiwebview/#more-1003

在调用该代码之前,我通过将它们添加到+ [NSOperationQueue mainQueue]返回的队列中排队了一些操作。这些操作旨在在后台执行,因为它们调用+ [NSData dataWithContentsOfURL:]。

一旦调用了运行循环上的方法,它就会执行我的排队操作,阻塞主线程并阻止应用程序启动。现在我已经通过确保在第三方代码执行之前不排队任何操作来获得解决方法,但是如果有人知道为什么会发生这种情况,以及如何在将来阻止它,我很乐意听到它。谢谢!

1 个答案:

答案 0 :(得分:1)

原因相当简单。您在主队列上排队操作。然后有人(这段代码)告诉主队列运行操作。您的运营已经开始这是您几乎从不手动运行主runloop的原因之一。它会导致各种奇怪的事情发生。

关于如何防止它:不要手动泵送主runloop,并打开针对库的错误(包括针对Apple在NSAttributedString initWithHTML:...中间运行主runloop)。

我不清楚为什么调用代码需要用户代理字符串。它通常不是你的业务,但它也是相当静态的,所以应该通过其他手段来确定(其中最重要的只是硬编码答案)。在不知道目标的情况下,我不确定用什么来取代它,但这种方法并不好。