【问题标题】:Network iOS : Background / MainThread?网络 iOS:背景/主线程?
【发布时间】:2014-08-03 12:31:11
【问题描述】:

我正在尝试将图像放入 cell.image。 如果图像已经加载(因此,在缓存中),我会这样做。否则,我使用sendAsynchronousRequest 在后台下载它。

这是我的代码:

var image = self.imageCached[urlString] as? UIImage
    
    if image {
        cell.imageView.image = image
    
    } else {
        
        let request = NSURLRequest(URL: NSURL(string: urlString))
        NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), { response, data, error -> Void in
            
            image = UIImage(data: data)
            self.imageCached[urlString] = image;
            
            dispatch_async(dispatch_get_main_queue(), {
                cell.imageView.image = image
            })
        })
    }

但是我还有一些不清楚的地方:

  1. NSURLConnection.sendAsynchronousRequest 在后台执行任务,但NSOperationQueue.mainQueue() 似乎在主线程中执行任务(因为名称为“mainQueue”)。那么真实的东西是什么?指令内的块是在后台还是主线程?因为如果它在主线程上,则无需返回主线程来更新 UI。

  2. 我听说NSURLConnection 用于小快速请求。是真的吗?因为当我使用NSURLSession 而不是这个异步的NSURLConnection 请求下载所有单元格图像时,它会比NSURLConnection 更长。

    那么我应该什么时候使用NSURLConnection,什么时候使用NSURLSession? (例如:json 数据或来自 api 的快速登录检查)

  3. 另外,当我退出应用程序时,系统缓存似乎有效。但是怎么做?因为我只是将图像存储在数组中。那么为什么关闭应用后,它似乎总是被缓存呢?

【问题讨论】:

  • 顺便说一句,如果这是在表/集合视图中,请记住,您不能假设 cell 在异步请求完成时仍然有效(因为单元格被重用)。通常,在 dispatch_async 块内,您将使用 cellForXXXAtIndexPath 查询表/集合视图(不要与视图控制器中类似命名的方法混淆)以查看单元格是否仍然可见,并使用新的用于更新图像的指针。
  • 好的,那么调度外的单元格(在第一个 if 中),它可能是无效的?
  • 第一个(你说if image ...)很好,因为这是在cellForRowAtIndexPath 的流程中同步发生的。但是异步请求中的任何内容(例如在sendAsynchronousRequest 中)或dispatch_async 中的任何内容都应该在尝试使用之前检查单元格是否仍然可见。如果您不这样做,尤其是在连接速度较慢的情况下,您可能会看到更新了错误的单元格(有时表现为单元格图像从一个到另一个闪烁)。

标签: ios multithreading background nsurlconnection nsurlsession


【解决方案1】:
  1. queue 参数指定完成块将在哪个队列上运行,而不是网络操作将在哪个队列上执行。

    顺便说一句,这意味着在完成块/闭包的当前实现中对主队列的额外调度是多余的。

    请注意,有点令人惊讶的是,imageWithData 本身(尤其是在图像很大的情况下)可能需要超过几毫秒的时间来运行,如果你在主线程中做imageWithData。通常你甚至不会注意到这一点,但如果这段代码在表格/集合视图中,你会在快速滚动时看到它。因此,您可能希望使用 mainQueue 以外的操作队列作为网络请求的 queue 参数,然后保留将最终 UI 更新分派到主队列的代码。差异可能几乎看不出来,但如果您想保持滚动如丝般顺滑,这是一个需要考虑的改进。这仅取决于此代码出现的上下文。

  2. 我的经验不是NSURLSessionNSURLConnection 慢。我想知道(尤其是没有看到NSURLSession 实现的代码),如果您的NSURLSession 实现由于某种原因没有缓存。

    一般法律顾问是,如果您需要支持 7.0 之前的 iOS 版本,您将使用 NSURLConnection,否则使用 NSURLSession

  3. 您看到的缓存是由NSURLConnection 和/或NSURLSession 透明提供的,与您可能对阵列有效执行的任何应用级缓存完全分开。

【讨论】:

  • 感谢您的回复。关于1)我什么都不懂^^
  • 在第 2 点,我看到您与我们简要分享的 NSURLSession 示例,但没有看到任何明显的内容。我刚刚比较了NSURLSession.sharedSession()NSURLSession(configuration)NSURLConnection.sendAsynchronousRequest,它们具有可比性,所以如果没有更多信息(包括展示您描述的行为的示例 URL),我无法发表评论。我唯一想知道的是,这两个类之间的默认缓存可能存在差异(Apple 从未对具体标准非常开放),但这可以通过显式指定缓存来解决。
  • 对不起,关于 Rob,这只是我的一个错误。没关系。但就像我说的,现在不是 2) 问题,而是 1) .. 无论如何,谢谢你所做的。
  • 对不起,我不清楚你是否还有任何问题,或者我是否已经回答了......
猜你喜欢
  • 1970-01-01
  • 2011-10-29
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 2013-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多