打破Managed Object和Collection View Cell之间的强引用循环

时间:2015-01-17 05:31:50

标签: ios swift core-data uicollectionviewcell strong-references

更新:

与Core Data或CollectionView无关。我从未解除持有CollectionView的ViewController。更多在下面的答案!


我在Swift iOS中遇到内存泄漏。首先我认为它位于我的fetch函数中,但后来我尝试了不同的东西。我在各个地方打破了UICollectionViewCellManaged Object之间的联系。我正在拍摄图像。所以我用一个随机图像资源替换了我的fetch结果,该资产被添加到数组中的次数与结果一样多。这总是修复我的泄漏。所以现在我知道在我的fetch函数中没有问题,在去Cell的途中还有其他任何功能。

经过一些谷歌搜索后,我发现Core Data有一些倾向于自己创建强大的参考周期。但我不认为就是这样。如果是的话,我不会在Cell中使用生成的图像数组。我仍然应该有泄漏,但是当我没有将Core Data中的图像连接到Cell时,我没有泄漏。

我不明白的是为什么我一开始就有泄漏。我认为数组的工作方式与值相似,而不是引用。因此,将从核心数据加载的图像放在一个数组中应该像副本一样工作,不应该有任何强大的参考周期......

我还发现刷新具有图像的二进制数据属性的托管对象并不能解决问题。

那我现在该怎么办?我需要删除所有单元格吗?我是否需要从核心数据中取出NSData中的UIImages(瞥了一眼说Strings的工作方式就像值,但NSStrings没有,所以也许NSData的东西就像参考一样)?我是否需要找到一种刷新对象属性的方法?...

谢谢!

抓取(也尝试将设置为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中输入图像(thumb是变量数组=> [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!
    }

1 个答案:

答案 0 :(得分:2)

问题在于你的故事板中有一个循环。您正从视图控制器A推动到视图控制器B,然后从视图控制器B推回"返回"每次都要查看控制器A.等等。因此,您的导航控制器只会堆积相同视图控制器的大量副本。所以你最终得到了所有这些图像的大量副本。

当你做这类事情时,你不会得到通知,这让我感到惊讶。这是一个经典的错误,而且很容易制作。当然Interface Builder可以检测到这种循环并警告你。但它没有......