My environment is Xcode 7.2, OS X 10.10.5, and an ARC project.
I've been tracking a problem with an ever-expanding memory footprint for a Mac application that uses a NSCollectionView. I believe I now understand what's happening but haven't found a way to fix it.
To mimic my original problem, I created a test app which has the NSCollectionView's content refreshed by a timer every two seconds. If the app is left untouched (either as the foremost application or not), Instruments shows the number of NSCollectionViewItem objects, along with their views, and model objects continuously increasing.
(I can provide sample code if desired but it's all really simple with bindings between a collection view and an array controller, the controller and an array, and labels to the represented object fields.)
Here's a sample retain history for my NSCollectionViewItem subclass:
0 Malloc +1 1 00:42.242.076 Foundation _decodeObjectBinary
Retain/Autorelease/Release (3) 00:42.242.093 Foundation _decodeObjectBinary
4 Retain +1 2 00:42.242.717 Foundation _decodeObjectBinary
5 Retain +1 3 00:42.242.718 Foundation -[NSKeyedUnarchiver _replaceObject:withObject:]
6 Release -1 2 00:42.242.718 Foundation _decodeObjectBinary
7 Retain +1 3 00:42.242.719 Foundation _decodeObjectBinary
8 Autorelease 00:42.242.721 AppKit -[NSCollectionViewItem copyWithZone:]
9 Retain +1 4 00:42.242.722 AppKit -[NSCollectionViewItem copyWithZone:]
10 Release -1 3 00:42.242.733 Foundation -[NSKeyedUnarchiver dealloc]
11 Release -1 2 00:42.242.742 Foundation -[NSKeyedUnarchiver dealloc]
Retain/Release (4) 00:42.243.993 Foundation _NSSetObjectValueAndNotify
Retain/Release (4) 00:42.244.032 Foundation _NSSetObjectValueAndNotify
20 Autorelease 00:42.244.117 AppKit -[NSCollectionView setContent:]
21 Retain +1 3 00:42.244.118 AppKit -[NSCollectionView _getItemsToDisplay]
22 Retain +1 4 00:42.246.179 AppKit -[NSCollectionView _displayItems:withConfiguration:animate:]
23 Retain +1 5 00:42.246.903 AppKit __60-[NSCollectionView _displayItems:withConfiguration:animate:]_block_invoke_2
24 Retain +1 6 00:42.247.334 QuartzCore +[CATransaction setCompletionBlock:]
25 Release -1 5 00:42.248.393 AppKit -[NSCollectionView _displayItems:withConfiguration:animate:]
Release (2) -2 00:42.250.725 Foundation __NSFireTimer
28 Release -1 2 00:42.250.984 Foundation __NSFireTimer
29 Release -1 1 00:42.255.196 AppKit _DPSNextEvent
30 Retain +1 2 00:44.242.063 AppKit -[NSCollectionView _displayItems:withConfiguration:animate:]
31 Release -1 1 00:44.242.066 AppKit -[NSCollectionView _displayItems:withConfiguration:animate:]
32 Retain +1 2 00:44.242.311 AppKit -[NSCollectionView _displayItems:withConfiguration:animate:]
33 Release -1 1 00:44.244.136 Foundation __NSFireTimer
34 Release -1 0 00:44.544.908 AppKit __49-[NSCollectionView _scheduleEndOfAnimationTimer:]_block_invoke
35 Retain +1 2 00:44.544.908 AppKit -[NSAutounbinder retainBindingTargetAndUnbind]
If an event such as mouse down or mouse moved is delivered to the application, the accumulated memory is released, as in:
36 Release -1 0 02:36.040.659 AppKit -[NSAutounbinder dealloc]
37 Free 0 02:36.040.669 AppKit -[NSResponder dealloc]
Obviously, telling users to keep the app active and shake the mouse now and then isn't a great solution. 🙂 Is there a way this is supposed to work?
(My attempts to send a fake mouse event to my own app at the end of the timer cycle haven't worked. Perhaps I'm doing it wrong; perhaps something is smart enough to know it's not an external event.)