【问题标题】:Using Runloop in inside nsoperation for async tasks在 nsoperation 内部使用 Runloop 执行异步任务
【发布时间】:2016-09-22 22:42:53
【问题描述】:

我有一个用例,我需要使用 NSURLSession 下载许多文件。

为了防止会话任务超时,我需要将它们放在操作队列中并限制并发下载量,以免它们饿死。

我的想法是将任务恢复加载到 nsoperation 中,并将它们加载到 nsoperationqueue 中,这将限制并发活动的数量。

问题是,当我调用 [task resume] 时,代码将退出并且 nsoperation 将认为自己完成,即使我正在等待文件完成下载。

这是一些代码。

NSURLSessionDownloadTask *task = [session downloadTaskWithRequest: request 
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {

     //move the file to a permanent location

     CFRunLoopStop(CFRunLoopGetCurrent());
}
//I have instantiated a class global NSOperation queue.
[imageDownloadQueue addOperationWithBlock:^void() {
     [task resume];
     CFRunLoopRun();
}];

在等待回调时如何保持 nsoperation 线程处于活动状态?我也尝试过使用 nsrunloop 并向 NSMachPort 添加一个端口。这似乎没有帮助。

此外,在 NSURLSession 上设置 HttpMaximumConnectionsPerHost 也无济于事,因为超时计时器在我恢复任务时启动。这意味着我将获得比以前更多的超时。

【问题讨论】:

  • 请参阅developer.apple.com/videos/play/wwdc2015/226(WWDC 2015 Advanced NSOperations),它广泛讨论了这类问题。一年后,我就这些模式向 Dave DeLong 提出质疑,看看他是否仍然认为它们有效。他说它继续非常成功。
  • 这是一个很好的视频,但我没有时间重写模式。它所涉及的代码比这要多得多。我只想让线程保持活动状态并让回调自行删除。
  • 这就是异步 NSOperations 的用途。您创建一个自定义 NSOperation,为 isAsynchronous 返回 true,并覆盖 start() 而不是 main()。您必须在适当的时间(即您的操作完成时)手动设置isExecutingisFinished。您不希望“线程保持活力”。您希望操作在正确的时间将自己标记为完成。这就是异步操作的工作方式。这只是意味着您手动完成,而不是“当main() 返回时”。

标签: ios multithreading nsurlsession nsoperation cfrunloop


【解决方案1】:

遗憾的是,我没有时间进行适当的修复,我需要尽快修复超时问题。我发现了一些有效的方法。

    //I have instantiated a class global NSOperation queue.
[imageDownloadQueue addOperationWithBlock:^void() {
     [task resume];
     while(task.state == NSURLSessionTaskStateRunning)
    {
         [NSThread sleepForTimeInterval:.1];
    }
    }];

由于 NSOperation 在后台线程上工作,我能够在任务运行时休眠该线程。这可以防止线程死亡,但任务将在它自己的线程上运行并且不会被阻塞。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    相关资源
    最近更新 更多