NSURLSession 和 NSDefaultRunLoopMode

Posted

技术标签:

【中文标题】NSURLSession 和 NSDefaultRunLoopMode【英文标题】:NSURLSession and NSDefaultRunLoopMode 【发布时间】:2013-11-20 14:07:47 【问题描述】:

使用NSURLConnection 时,您可以选择使用NSRunLoop 安排连接:

- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode

如果用户滚动,传递NSDefaultRunLoopMode 将有效地导致连接暂停,这对性能很有好处,因为用户体验从未受到下载的影响。

有没有办法让NSURLSession 出现类似的行为?我已阅读文档并尝试了各种配置会话的方法,但均未成功。

【问题讨论】:

【参考方案1】:

NSURLSession 在“上层”工作,对开发人员来说比使用NSURLConnection 更简单。 我做了一些测试,我认为不可能控制 NSURLSession 的运行循环和模式,因为它们似乎是由外部守护进程而不是你的应用程序管理的(我只用 NSURLSessionDownloadTask 进行了测试)。 做这个简单的测试:

    下载并执行this Github project 开始下载 打开“下载”控制器查看下载状态 暂停应用 等一下 取消暂停应用

您会看到在您的应用暂停时继续下载,因此当您启动 NSURLSession 时,控制权会传递给系统,在您的应用之外:这意味着工作的主要部分没有发生在内部 runLoop 中。

您唯一可以控制的是调度委托调用的串行队列(传递回您的应用程序)。委托调用排队等待执行(在主线程或后台线程上,您可以选择它),因为NSOperationQueue 使用 Grand Central Dispatch 将调用排队,我不确定用于此的运行循环模式,但是我认为这是继续您的研究的一个很好的起点。

编辑: 如果我没记错的话,在后台线程上进行的调度调用是在没有运行 runloop 的线程上进行的。其实如果加这行

NSLog(@"%@", [[NSRunLoop currentRunLoop] currentMode]);

在上一个项目中FLDownloader类的一个委托方法上,你会看到没有运行模式(nil),当runloop没有运行时会发生这种情况。

【讨论】:

您正在使用后台会话配置,这导致您的任务在进程外进行管理。非后台会话在应用程序管理的线程上运行。我同意似乎不可能做我想做的事。 我不确定这个,但我很好奇这个论点并做了一些研究。如果你分析一个新创建的 NSURLSession(非后台)的整个堆栈跟踪,有一些方法调用属于 runloops。例如[NSURLConnection, _resourceLoadLoop:][NSURLConnection, resourceLoaderRunLoop]。我试图调配第二个,它让我可以访问 CFRunLoop 对象(作为返回值)。也许你可以尝试用它作弊并改变 NSURLSession 的模式(如果我理解正确,似乎 NSURLSession 使用 kCFRunLoopDefaultMode) 有趣的是,我也在跟踪中看到了 resourceLoadLoop,但没有进一步研究它。不过,我不想对此进行破解,如果不支持,我将坚持在默认模式下运行的标准行为。【参考方案2】:

如果有人再次遇到这个问题。您不能将下载任务安排到不同的运行循环中,但您可以在不同的运行循环模式下处理响应,这仍然大大提高了滚动时的性能。

[self performSelectorOnMainThread:@selector(requestDidFinishLoadingWithData:)
                       withObject:data
                    waitUntilDone:YES
                            modes:@[NSDefaultRunLoopMode]];

【讨论】:

以上是关于NSURLSession 和 NSDefaultRunLoopMode的主要内容,如果未能解决你的问题,请参考以下文章

NSURLSession 委托跨类拆分 - NSURLSession、NSURLUploadTask、NSURLDownloadTask

使用 NSURLSession 异步下载数据和处理

NSURLSession 和 NSDefaultRunLoopMode

NSURLSession 和 API

客户端证书和 NSURLSession

iOS开发网络篇—发送GET和POST请求(使用NSURLSession)