我在使用 swift 将数据导入 coredata 项目时遇到问题。我导入了很多图像,这导致了相当大的内存占用(大约 100 - 120MB)。问题是,一旦下载并导入了图像,我就会保存 managedObjectContext 并重置它,但内存没有释放。但是,如果我将应用程序发送到后台,则大部分内存都会释放(我最终得到~50MB)。
我使用以下 CoreData 设置:
- 一个
masterContext
与PrivateQueueConcurrencyType
- 一个
mainContext
MainQueueConcurrencyType
和masterContext
作为parentContext
- 导入在它自己的上下文中运行,
PrivateQueueConcurrencyType
和mainContext
因为它是parentContext
以下方法开始导入:
func downloadProductImages(completion: (error: NSError?) -> Void) {
if let moc = self.backgroundMOC {
moc.performBlock { () -> Void in
moc.reset()
var err: NSError? = nil
self.importBrandImages({ (error) -> Void in
if error != nil {
completion(error: error)
return
}
moc.save(nil)
self.importProductVariantThumbnails({ (error) -> Void in
if error != nil {
completion(error: error)
return
}
moc.save(nil)
moc.reset()
self.backgroundMOC = nil
completion(error: err)
})
})
}
}
}
这些方法下载图像并将它们保存在数据库中:
private func importBrandImages(completion: (error: NSError?) -> Void) {
if let moc = self.backgroundMOC {
moc.performBlock { () -> Void in
moc.reset()
var error: NSError? = nil
let brandsFetchReq = NSFetchRequest(entityName: "Brand")
// brand images
if let brands = moc.executeFetchRequest(brandsFetchReq, error: &error) as? [Brand] {
let imageQueue = TaskQueue()
autoreleasepool({ () -> () in
for brand in brands {
if let logoSrc = brand.logoSrc {
imageQueue.tasks +=~ { results, next in
ImageLoader.sharedLoader.imageForUrl(logoSrc.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!, completionHandler: { (image, url) -> () in
if image != nil {
brand.logo = UIImageJPEGRepresentation(image, 0.35)
}
next(nil)
})
}
}
if let bgImgSrc = brand.bgImageSrc {
imageQueue.tasks +=~ { results, next in
ImageLoader.sharedLoader.imageForUrl(bgImgSrc.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!, completionHandler: { (image, url) -> () in
if image != nil {
brand.bgImage = UIImageJPEGRepresentation(image, 0.35)
}
next(nil)
})
}
}
}
})
imageQueue.run(completion: { () -> Void in
moc.save(nil)
completion(error: error)
})
} else {
completion(error: error)
}
}
}
}
private func importProductVariantThumbnails(completion: (error: NSError?) -> Void) {
var err: NSError? = nil
if let moc = self.backgroundMOC {
moc.performBlock { () -> Void in
moc.reset()
let pVariantsFetchReq = NSFetchRequest(entityName: "ProductVariant")
if let variants = moc.executeFetchRequest(pVariantsFetchReq, error: &err) as? [ProductVariant] {
let importQueue = TaskQueue()
autoreleasepool({ () -> () in
for variant in variants {
if let thumbnailSrc = variant.thumbnailSrc {
importQueue.tasks +=~ { results, next in
ImageLoader.sharedLoader.imageForUrl(thumbnailSrc.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!, completionHandler: { (image, url) -> () in
if image != nil {
variant.thumbnail = UIImageJPEGRepresentation(image, 0.35)
}
next(nil)
})
}
}
}
})
importQueue.run { () -> Void in
moc.save(nil)
self.importProductVariantImages({ (error) -> Void in
completion(error: error)
})
}
}
}
}
}
private func importProductVariantImages(completion: (error: NSError?) -> Void) {
var error: NSError? = nil
if let moc = self.backgroundMOC {
moc.performBlock { () -> Void in
moc.reset()
let pImagesFetchReq = NSFetchRequest(entityName: "ProductImage")
// product images
if let images = moc.executeFetchRequest(pImagesFetchReq, error: &error) as? [ProductImage] {
let importQueue = TaskQueue()
autoreleasepool({ () -> () in
for pImage in images {
if let imageSrc = pImage.imageSrc {
importQueue.tasks +=~ { results, next in
ImageLoader.sharedLoader.imageForUrl(imageSrc.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!, completionHandler: { (image, url) -> () in
if image != nil {
pImage.imageData = UIImageJPEGRepresentation(image, 0.35)
}
next(nil)
})
}
}
}
})
importQueue.run(completion: { () -> Void in
moc.save(nil)
completion(error: error)
})
} else {
completion(error: error)
}
}
}
}
我不知道,为什么不释放记忆。我使用仪器来查找内存泄漏,但它没有显示任何内存泄漏。
您的问题似乎是ImageLoader
包含缓存并将所有图像添加到其中。如果您不需要该功能,并且它看起来并不像您那样,那么您应该删除它并简化ImageLoader
以便它只下载并返回图像。