iOS Swift CoreData 异步下载图片数据

Posted

技术标签:

【中文标题】iOS Swift CoreData 异步下载图片数据【英文标题】:iOS Swift CoreData Asynchronous Downloading of Image Data 【发布时间】:2015-01-19 14:25:56 【问题描述】:

作为一个对 Swift 和 CoreData 很陌生的人,我确信我的做法是错误的,希望有人能提供帮助。

背景:我正在通过 API 下载 JSON,并在 iPad 上的 CoreData 中本地缓存内容。作为该过程的一部分,我需要下载一个小图像缩略图,并将其存储在 CoreData 中(作为 Transformable)。

我在做:我的原始实现下载了图像并将它们保存到 CoreData,但是虽然它是从后台线程触发的(API 调用之后的回调),但图像的实际下载似乎导致应用挂起:

let data = NSData(contentsOfURL: imgURL)
if let imageData = data 
    coreDataEntity.thumbnail = imageData

我现在在做什么:我已经将我的代码更新为以下内容:

func downloadImage(url: NSURL, cdEntity: CoreDataEntity, moc: NSManagedObjectContext, handler: ((image: UIImage?, cdEntity: CoreDataEntity, moc: NSManagedObjectContext, NSError!) -> Void))

    var imageRequest: NSURLRequest = NSURLRequest(URL: url)
    NSURLConnection.sendAsynchronousRequest(imageRequest,
        queue: NSOperationQueue.mainQueue(),
        completionHandler: response, data, error in
             handler(image: UIImage(data: data), cdEntity: cdEntity, moc: moc, error)
    )


func setImage(image: UIImage?, cdEntity: CoreDataEntity, moc: NSManagedObjectContext, error: NSError?) 
    cdEntity.thumbnail = image
    save(moc)

然后我这样调用代码:

downloadImage(imgURL, coreDataEntity, moc,  (image, cdEntity, moc, error) -> Void in
    setImage(image, cdEntity, moc, error)
)

这样做,我注意到主线程上没有任何块。从设备检查 sqlite 文件,看起来数据设置正确,但图像未显示在 UI 中。

我的方法完全错误吗?如果不是,我如何通知 UI 核心数据模型已以导致刷新的方式更新?可以调用什么函数来更新表格/uicollectionview的特定行/单元格?

【问题讨论】:

"并在 CoreData 中将内容本地缓存到 iPad 上。"呃……为什么? URL 加载系统已经在为您处理缓存。如果您想将缓存的数据持久化到磁盘,您只需将其打开即可。请参阅NSURLCache 的文档。 我很高兴研究替代缓存选项,但指向图像(存储在 S3 上)的 URL 可能会随着新令牌的生成而发生变化以授予对它的访问权限。我的假设是这会使 NSURLCache 无效。 【参考方案1】:

    您的 NSURLConnection 的回调发生在主队列上。这是您的应用程序被锁定的原因之一。

    您的托管对象上下文(至少在您发布的代码中)没有遵循 Core Data 并发规则。您可以在线程限制(不幸的是,默认设置,已过时)和队列限制之间进行选择。

使用线程限制,您只能使用创建它的线程中的托管对象上下文。如果您在主线程(或队列)上创建托管对象上下文,则只能从那里使用它 - 因此您在该上下文上执行的任何 Core Data 操作都会阻塞主线程,进而阻塞 UI。

使用队列限制(几乎)任何对托管对象上下文的操作都必须通过performBlock:performBlockAndWait: 方法。入队的块在上下文的串行队列上执行。这比线程限制更不容易出错,并且自 ios 5 以来一直是并发的推荐做法。

如果没有,我如何通知 UI 核心数据模型已以导致刷新的方式更新?可以调用什么函数来更新表格/uicollectionview的特定行/单元格?

这通常使用NSFetchedResultsController 来完成,它会观察托管对象上下文中与其获取请求相关的更改。一旦初始获取填充控制器,它将侦听影响获取请求指定的对象的上下文更改。当发生相关更改时,控制器会通过回调通知它的委托。

【讨论】:

以上是关于iOS Swift CoreData 异步下载图片数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 Core Data 在 Swift 中通过 UIProgressView 异步插入数据

在异步任务中快速返回 Firebase

Swift 在 UITableView 中异步加载图像 - 顶部单元格没有图片

Swift/IOS/CoreData:如何在自动生成的 CoreData 类中将 var 定义为枚举类型?

执行网络调用并继续 - 异步任务

iOS-UIImageView载入网络下载的图片(异步+多线程)