Update :
Had nothing to do with Core Data or the CollectionView. I never dismissed the ViewController holding the CollectionView. More in the answer below!
I am having a memory leak in Swift iOS. First I thought it was located in my fetch function, but then I tried something different. I broke the connection between my UICollectionViewCell
and my Managed Object
at various places. I am fetching images. So I replaced the result from my fetch with a random image asset that was added to an array for as many times as there were results. This always fixed my leak. So now I knew it wasn't a problem in my fetch function, any other function on the way to the Cell.
After some googling I found that Core Data has some tendency to create strong reference cycles on it's own. But I don't think that that is it. If it was, it shouldn't matter that I don't use the resulting array of images in a Cell. I should still have a leak, but when I don't connect the images from Core Data to the Cell I have no leak.
What I don't understand is why I have a leak in the first place. I thought that arrays work like values, not references. So putting images loaded from core data in an array should work like a copy and there shouldn't be any strong reference cycle...
I also found that refreshing the Managed Object that has the Binary Data atribute for the images doesn't fix the problem.
So what do I do now? Do I need to delete all the cells? Do I need to make UIImages out of the NSData from Core Data (glanced over something that said that Strings work like values but NSStrings don't, so maybe an NSData thingy works like a reference)? Do I need to find a way to refresh the attribute of an object?...
Thanks!
Fetch(also tried setting things as weak
, doesn't work):
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)
}
}
Input images in Cell(thumbs is a variable array => [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!
}