问题
I have noticed a memory leak in NSCollectionView through Instruments. When I track down to the code, it shows the specific line below:
collectionView.makeItem(withIdentifier: identifier, for: indexPath) as? DisplayableCellProtocol
Then I looked it in Xcode, memory debugger, and find out there are some non-referenced items that caused the leak. However, not all items created by makeItem
is leaking, some of them are normal, but some are not even shown.
Managed normal unleaked item is like this graph
And the leaked ones are like this (without any connections):
Is that normal, does anyone else has the same problem? Does anyone know how to correctly solve this problem? Does this have anything to do with using xib to design the items views?
Here are some code that may be helpful to understand the situation:
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let data = datasource[indexPath.item]
let identifier: String = "ServiceCell"
// Next line is where the leak occurs
guard let cell = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: identifier), for: indexPath) as? ServiceCell else {
return ServiceCell(nibName: NSNib.Name("ServiceCell.xib"), bundle: Bundle.main)
}
cell.iconView.image = data.icon
cell.serviceLabel.stringValue = data.name
cell.introLabel.stringValue = data.content
cell.highlighted = false
return cell
}
The definition of ServiceCell is:
class ServiceCell: NSCollectionViewItem {
@IBOutlet weak var iconView: NSImageView!
@IBOutlet weak var serviceLabel: NSTextField!
@IBOutlet weak var cmdLabel: NSTextField!
@IBOutlet weak var introLabel: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
}
Not sure if the code is helpful here. I have tried to find if there is any bug in my own code, but have not found any yet.
Meanwhile, I found a lot of other leaks, and most of them points to the makeItem
line
Update: I have looked through it again. So every time it will double the number of items that is actually needed. For example, I need 2 cells, it will create 4 instead of 2, and two of them is the leaked ones. Any ideas?
回答1:
This is finally solved. When creating a class inherited from NSCollectionViewItem
with creating an xib file, the class of the File Owner in the xib is set to the subclass created before by default. When we add a custom object in the xib, this needs to be set empty.
回答2:
I assume you're seeing this issue if your delegate
and dataSource
are (weakly?) set to the NSCollectionView itself. I had this slightly questionable setup on MacOSX 10.14.6.
With the delegates so-wired in, I questionably "solved" this by introducing empty stubs for willDisplayItem and didEndDisplayingItem. With that, the memory leaks went away.
My collection view content was 48 items; without these stubs, the first return from itemForRepresentedObjectAtIndexPath (which called makeItemWithIdentifier) beach-balled my app with memory usage shooting through the roof.
I'm in the process now of relocating this collection view into an NSViewController
to avoid these shenanigans.
来源:https://stackoverflow.com/questions/50916659/nscollectionview-memory-leak-in-high-sierra