I have a table view that contains images <1mb in size. When I scroll, I pull each image from my server and then save it to CoreData, unless it is already local (for purpose of a Cache).
我有一个包含小于1mb大小的图像的表视图。当我滚动时,我从我的服务器上提取每个图像,然后将其保存到CoreData,除非它已经是本地的(用于缓存)。
Here is the function I use to save each image to core data...
这是我用来将每个图像保存到核心数据的函数……
// MARK: - Save Image to Core Data
func saveImageToCoreData(url: String,imageData: NSData) {
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
if let managedContext = appDelegate.managedObjectContext as? NSManagedObjectContext {
let privateMoc = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMoc.parentContext = managedContext
let entity = NSEntityDescription.entityForName("Images",
inManagedObjectContext: privateMoc)
let options = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: privateMoc)
options.setValue(url, forKey: "url")
options.setValue(imageData, forKey: "imageData")
privateMoc.performBlock({
do {
try privateMoc.save()
print("Successfuly Saved an Image to Core Data.")
do {
try managedContext.save()
} catch {
}
} catch {
// Failed to save
}
})
}
}
}
If I scroll slowly, it works fine. However, when this function is called by scrolling quickly and thus calling 'cellForRowAtIndexPath' many times, it gives me errors and crashes.
如果我慢慢地滚动,它会工作得很好。但是,当快速滚动调用这个函数并多次调用“cellForRowAtIndexPath”时,它会给我带来错误和崩溃。
Error Example: CoreData: error: (1555) UNIQUE constraint failed: ZIMAGES.Z_PK
错误示例:CoreData: Error:(1555)唯一约束失败:zimage . z_pk
Is my Save function incorrect? Or perhaps there is an issue with setting up so many threads at once to perform a save function?
我的保存功能不正确吗?或者,一次设置这么多线程来执行保存函数可能会有问题?
Any ideas are much appreciated! Thanks!
非常感谢您的建议!谢谢!
2 个解决方案
#1
1
There are several problems with your save function:
1. You are creating a private queue context for each image, which is not really a good idea. The better way is to create one single private queue context, and use it for saving all the images.
2. Do not call this save image function in cellForRowAtIndexPath
, since this delegate function will be called multiple times when scrolling the tableview up and down. Just do it somewhere else, like inside the download image completion call back.
3. Since CoreData is not thread safe, you must insert new image on the private context's thread instead of main thread. So you have to do this:
保存函数有几个问题:1。您正在为每个映像创建一个私有队列上下文,这并不是一个好主意。更好的方法是创建一个单独的私有队列上下文,并使用它保存所有映像。2。不要在cellForRowAtIndexPath中调用这个save映像函数,因为当上下滚动tableview时,将多次调用这个委托函数。只需要在其他地方做,比如在下载图像补全调用中。3所示。因为CoreData不是线程安全的,所以必须在私有上下文的线程上而不是主线程上插入新的映像。所以你必须这么做:
privateMoc.performBlock({
let entity = NSEntityDescription.entityForName("Images", inManagedObjectContext: privateMoc)
let options = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: privateMoc)
options.setValue(url, forKey: "url")
options.setValue(imageData, forKey: "imageData")
do {
try privateMoc.save()
print("Successfuly Saved an Image to Core Data.")
do {
try managedContext.save()
} catch {
}
} catch {
// Failed to save
}
})
After you making these three fixes, the issue should be resolved I believe.
在你做了这三个修正之后,我认为这个问题应该得到解决。
#2
0
May be you can use SDWebImage.
也许你可以使用SDWebImage。
#1
1
There are several problems with your save function:
1. You are creating a private queue context for each image, which is not really a good idea. The better way is to create one single private queue context, and use it for saving all the images.
2. Do not call this save image function in cellForRowAtIndexPath
, since this delegate function will be called multiple times when scrolling the tableview up and down. Just do it somewhere else, like inside the download image completion call back.
3. Since CoreData is not thread safe, you must insert new image on the private context's thread instead of main thread. So you have to do this:
保存函数有几个问题:1。您正在为每个映像创建一个私有队列上下文,这并不是一个好主意。更好的方法是创建一个单独的私有队列上下文,并使用它保存所有映像。2。不要在cellForRowAtIndexPath中调用这个save映像函数,因为当上下滚动tableview时,将多次调用这个委托函数。只需要在其他地方做,比如在下载图像补全调用中。3所示。因为CoreData不是线程安全的,所以必须在私有上下文的线程上而不是主线程上插入新的映像。所以你必须这么做:
privateMoc.performBlock({
let entity = NSEntityDescription.entityForName("Images", inManagedObjectContext: privateMoc)
let options = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: privateMoc)
options.setValue(url, forKey: "url")
options.setValue(imageData, forKey: "imageData")
do {
try privateMoc.save()
print("Successfuly Saved an Image to Core Data.")
do {
try managedContext.save()
} catch {
}
} catch {
// Failed to save
}
})
After you making these three fixes, the issue should be resolved I believe.
在你做了这三个修正之后,我认为这个问题应该得到解决。
#2
0
May be you can use SDWebImage.
也许你可以使用SDWebImage。