打破 Managed Object 和 Collectionview Cell 之间的强引用循环
break strong reference cycle between Managed Object and Collectionview Cell
更新:
与 Core Data 或 CollectionView 无关。我从未拒绝过持有 CollectionView 的 ViewController。更多内容在下面的答案中!
我在 Swift iOS 中发生内存泄漏。起初我以为它位于我的获取函数中,但后来我尝试了一些不同的东西。我在多个地方断开了 UICollectionViewCell
和 Managed Object
之间的连接。我正在获取图像。因此,我用一个随机图像资产替换了我获取的结果,该资产被添加到数组中的次数与结果的次数一样多。这总能解决我的漏洞。所以现在我知道这不是我的 fetch 函数的问题,而是通往 Cell 的任何其他函数。
经过一番谷歌搜索后,我发现 Core Data 倾向于自行创建强大的引用循环。但我不认为就是这样。如果是的话,我不在 Cell 中使用生成的图像数组应该无关紧要。我应该仍然有泄漏,但是当我不将图像从 Core Data 连接到 Cell 时,我没有泄漏。
我不明白的是为什么我一开始就漏水了。我认为数组像值一样工作,而不是引用。因此,将从核心数据加载的图像放在数组中应该像副本一样工作,并且不应该有任何强引用循环...
我还发现刷新具有图像二进制数据属性的托管对象并不能解决问题。
那我现在该怎么办?我需要删除所有单元格吗?我是否需要从 Core Data 的 NSData 中制作 UIImages(浏览了一些说字符串像值一样工作但 NSStrings 没有的东西,所以也许 NSData 东西像参考一样工作)?我需要想办法刷新对象的属性吗?...
谢谢!
Fetch(也尝试将其设置为 weak
,无效):
import UIKit
import CoreData
func getFilteredThumbImages (albumIdentifier: String, moc : NSManagedObjectContext?) -> [NSData]? {
var error: NSError?
let resultPredicate = NSPredicate(format: "iD = %@", albumIdentifier)
let albumfetchRequest = NSFetchRequest(entityName: "Album")
albumfetchRequest.predicate = resultPredicate
var results = moc!.executeFetchRequest(albumfetchRequest, error:&error)!
if error == nil {
weak var tempFThumbs = results.last!.mutableSetValueForKey("filteredThumbs")
weak var testFoundImages = tempFThumbs!.mutableSetValueForKey("imageData")
var foundImages = testFoundImages!.allObjects as [NSData]
moc!.refreshObject(results.last! as NSManagedObject, mergeChanges: false)
moc!.reset()
return foundImages
}
else {
moc!.refreshObject(results.last! as NSManagedObject, mergeChanges: false)
//appDel?.managedObjectContext?.reset()
moc!.reset()
return nil
}
}
UICollectionViewCell :
import UIKit
class CollectionViewCell: UICollectionViewCell {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
let textLabel: UILabel!
let imageView: UIImageView!
override init(frame: CGRect) {
NSLog("MyObject init")
super.init(frame: frame)
imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
imageView.backgroundColor = UIColor(red:1, green:0.992, blue:0.965, alpha:1)
imageView.contentMode = UIViewContentMode.ScaleAspectFit
imageView.clipsToBounds = true
contentView.backgroundColor = UIColor(red:1, green:0.992, blue:0.965, alpha:1)
contentView.addSubview(imageView)
}
}
在Cell中输入图片(thumbs是一个变量数组=> [NSData]):
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
println("loading...")
weak var cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as? CollectionViewCell
//cell!.imageView?.image = UIImage(named: "test")
if thumbs != nil {
cell!.imageView?.image = UIImage(data: thumbs![indexPath.row])
println("loading \(thumbs!.count) cells")
}
return cell!
}
问题是你的情节提要中有一个循环。您从视图控制器 A 推送到视图控制器 B,然后从视图控制器 B "back" 推送到视图控制器 A。依此类推,每次。因此,您的导航控制器只是堆积了相同视图控制器的大量副本。所以你最终得到了所有这些图像的大量副本。
当你做这种事时,你没有得到通知,这总是让我感到惊讶。这是一个典型的错误,而且很容易犯。 Interface Builder 肯定可以检测到这种循环并警告您。但它没有...
更新:
与 Core Data 或 CollectionView 无关。我从未拒绝过持有 CollectionView 的 ViewController。更多内容在下面的答案中!
我在 Swift iOS 中发生内存泄漏。起初我以为它位于我的获取函数中,但后来我尝试了一些不同的东西。我在多个地方断开了 UICollectionViewCell
和 Managed Object
之间的连接。我正在获取图像。因此,我用一个随机图像资产替换了我获取的结果,该资产被添加到数组中的次数与结果的次数一样多。这总能解决我的漏洞。所以现在我知道这不是我的 fetch 函数的问题,而是通往 Cell 的任何其他函数。
经过一番谷歌搜索后,我发现 Core Data 倾向于自行创建强大的引用循环。但我不认为就是这样。如果是的话,我不在 Cell 中使用生成的图像数组应该无关紧要。我应该仍然有泄漏,但是当我不将图像从 Core Data 连接到 Cell 时,我没有泄漏。
我不明白的是为什么我一开始就漏水了。我认为数组像值一样工作,而不是引用。因此,将从核心数据加载的图像放在数组中应该像副本一样工作,并且不应该有任何强引用循环...
我还发现刷新具有图像二进制数据属性的托管对象并不能解决问题。
那我现在该怎么办?我需要删除所有单元格吗?我是否需要从 Core Data 的 NSData 中制作 UIImages(浏览了一些说字符串像值一样工作但 NSStrings 没有的东西,所以也许 NSData 东西像参考一样工作)?我需要想办法刷新对象的属性吗?...
谢谢!
Fetch(也尝试将其设置为 weak
,无效):
import UIKit
import CoreData
func getFilteredThumbImages (albumIdentifier: String, moc : NSManagedObjectContext?) -> [NSData]? {
var error: NSError?
let resultPredicate = NSPredicate(format: "iD = %@", albumIdentifier)
let albumfetchRequest = NSFetchRequest(entityName: "Album")
albumfetchRequest.predicate = resultPredicate
var results = moc!.executeFetchRequest(albumfetchRequest, error:&error)!
if error == nil {
weak var tempFThumbs = results.last!.mutableSetValueForKey("filteredThumbs")
weak var testFoundImages = tempFThumbs!.mutableSetValueForKey("imageData")
var foundImages = testFoundImages!.allObjects as [NSData]
moc!.refreshObject(results.last! as NSManagedObject, mergeChanges: false)
moc!.reset()
return foundImages
}
else {
moc!.refreshObject(results.last! as NSManagedObject, mergeChanges: false)
//appDel?.managedObjectContext?.reset()
moc!.reset()
return nil
}
}
UICollectionViewCell :
import UIKit
class CollectionViewCell: UICollectionViewCell {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
let textLabel: UILabel!
let imageView: UIImageView!
override init(frame: CGRect) {
NSLog("MyObject init")
super.init(frame: frame)
imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
imageView.backgroundColor = UIColor(red:1, green:0.992, blue:0.965, alpha:1)
imageView.contentMode = UIViewContentMode.ScaleAspectFit
imageView.clipsToBounds = true
contentView.backgroundColor = UIColor(red:1, green:0.992, blue:0.965, alpha:1)
contentView.addSubview(imageView)
}
}
在Cell中输入图片(thumbs是一个变量数组=> [NSData]):
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
println("loading...")
weak var cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as? CollectionViewCell
//cell!.imageView?.image = UIImage(named: "test")
if thumbs != nil {
cell!.imageView?.image = UIImage(data: thumbs![indexPath.row])
println("loading \(thumbs!.count) cells")
}
return cell!
}
问题是你的情节提要中有一个循环。您从视图控制器 A 推送到视图控制器 B,然后从视图控制器 B "back" 推送到视图控制器 A。依此类推,每次。因此,您的导航控制器只是堆积了相同视图控制器的大量副本。所以你最终得到了所有这些图像的大量副本。
当你做这种事时,你没有得到通知,这总是让我感到惊讶。这是一个典型的错误,而且很容易犯。 Interface Builder 肯定可以检测到这种循环并警告您。但它没有...