iOS Swift核心数据异步下载图像数据

时间:2015-01-19 14:25:57

标签: ios multithreading swift core-data

作为对Swift和CoreData很陌生的人,我确信我会以错误的方式解决这个问题,并希望有人能够提供帮助。

后台:我正在通过API下载JSON,并在CoreData中的iPad上本地缓存内容。作为整个过程的一部分,我需要下载一个小图像缩略图,我也将其存储在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中。

我的方法完全错了吗?如果没有,我如何通知用户界面核心数据模型已经以导致刷新的方式更新?可以调用什么函数来更新表/ uicollectionview的特定行/单元?

1 个答案:

答案 0 :(得分:2)

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

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

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

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

      

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

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