I have an NSCollectionView embedded in one of the tabs of an NSTabView. The collection is loaded and displays correctly, but upon switching to any other tab, the app crashes with the following crash log. The crash notes that an observer (ProjectTabLeadersCollection, which is the class of my NSCollectionView) cannot be removed for the key path "firstResponder". I'm not sure, exactly, what's going on, as I'm not explicitly registering any observers for this tab, so I'm assuming that AppKit is doing something behind the scenes, and my setup within either Interface Builder or my initialization code isn't quite correct. Hoping someone might have some guidance here.
Any ideas?
2022-04-12 07:21:53.861124-0700 APBA Baseball[78639:4002869] [General] Cannot remove an observer <ProjectTabLeadersCollection 0x7f9e6b8df1e0> for the key path "firstResponder" from <NSWindow 0x7f9e7c044500> because it is not registered as an observer.
2022-04-12 07:21:53.864095-0700 APBA Baseball[78639:4002869] [General] (
0 CoreFoundation 0x00007ff809bf41e3 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007ff809954c13 objc_exception_throw + 48
2 Foundation 0x00007ff80a9bf1ff -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] + 700
3 Foundation 0x00007ff80a9beeff -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] + 129
4 AppKit 0x00007ff80c77f736 -[NSCollectionView viewWillMoveToWindow:] + 274
5 AppKit 0x00007ff80c5b449a -[NSView _setWindow:] + 277
6 AppKit 0x00007ff80ce04884 __21-[NSView _setWindow:]_block_invoke.425 + 299
7 CoreAutoLayout 0x00007ff811211cf3 -[NSISEngine withBehaviors:performModifications:] + 84
8 AppKit 0x00007ff80c5b4b04 -[NSView _setWindow:] + 1919
9 AppKit 0x00007ff80ce04884 __21-[NSView _setWindow:]_block_invoke.425 + 299
10 CoreAutoLayout 0x00007ff811211cf3 -[NSISEngine withBehaviors:performModifications:] + 84
11 AppKit 0x00007ff80c5b4b04 -[NSView _setWindow:] + 1919
12 AppKit 0x00007ff80c62f07e -[NSScrollView _setWindow:] + 93
13 AppKit 0x00007ff80ce04884 __21-[NSView _setWindow:]_block_invoke.425 + 299
14 CoreAutoLayout 0x00007ff811211cf3 -[NSISEngine withBehaviors:performModifications:] + 84
15 AppKit 0x00007ff80c5b4b04 -[NSView _setWindow:] + 1919
16 AppKit 0x00007ff80c5e3d8f -[NSView removeFromSuperview] + 158
17 AppKit 0x00007ff80c7a230f __56-[NSView replaceSubview:with:options:completionHandler:]_block_invoke + 40
18 AppKit 0x00007ff80c7a2106 -[NSView replaceSubview:with:options:completionHandler:] + 735
19 AppKit 0x00007ff80c77996b -[NSTabView _switchTabViewItem:oldView:withTabViewItem:newView:initialFirstResponder:lastKeyView:] + 859
20 AppKit 0x00007ff80c772e21 -[NSTabView selectTabViewItem:] + 512
21 AppKit 0x00007ff80c7791b3 -[NSTabViewController setSelectedTabViewItemIndex:] + 637
22 AppKit 0x00007ff80c7a16fe -[NSApplication(NSResponder) sendAction:to:from:] + 288
23 AppKit 0x00007ff80c7a15a4 -[NSControl sendAction:to:] + 86
24 AppKit 0x00007ff80c7a14d6 __26-[NSCell _sendActionFrom:]_block_invoke + 131
25 AppKit 0x00007ff80c7a13df -[NSCell _sendActionFrom:] + 171
26 AppKit 0x00007ff80c89c311 -[NSSegmentedCell _sendActionFrom:] + 161
27 AppKit 0x00007ff80c79e19f NSControlTrackMouse + 1813
28 AppKit 0x00007ff80c79da66 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 121
29 AppKit 0x00007ff80c89ba45 -[NSSegmentedCell trackMouse:inRect:ofView:untilMouseUp:] + 712
30 AppKit 0x00007ff80c79cd06 -[NSControl mouseDown:] + 678
31 AppKit 0x00007ff80c79b1f1 -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 4859
32 AppKit 0x00007ff80c70f39e -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2582
33 AppKit 0x00007ff80c70e76e -[NSWindow(NSEventRouting) sendEvent:] + 352
34 AppKit 0x00007ff80c70cb44 -[NSApplication(NSEvent) sendEvent:] + 352
35 AppKit 0x00007ff80c9c596b -[NSApplication _handleEvent:] + 65
36 AppKit 0x00007ff80c58e35e -[NSApplication run] + 623
37 AppKit 0x00007ff80c5622b7 NSApplicationMain + 817
38 APBA Baseball 0x00000001058f8e22 main + 34
39 dyld 0x0000000109b1951e start + 462
The NSCollection is inside a tab called Leaders, and connections appear like so:
Here is the header for the collection:
@interface ProjectTabLeadersCollection : NSCollectionView <NSCollectionViewDataSource, NSCollectionViewDelegate> {
NSMutableArray *ar;
}
@end
Next, the .m file:
#import "ProjectTabLeadersCollection.h"
#import "ProjectTabLeadersCollectionItem.h"
@implementation ProjectTabLeadersCollection
-(void) viewDidMoveToWindow {
self.delegate = self;
self.dataSource = self;
ar = [[NSMutableArray alloc] init];
for (int i = 0; i < 100; ++i)
[ar addObject:@"Hello"];
}
- (void)collectionView:(NSCollectionView *)collectionView willDisplayItem:(nonnull NSCollectionViewItem *)item forRepresentedObjectAtIndexPath:(nonnull NSIndexPath *)indexPath {
}
- (void)collectionView:(NSCollectionView *)collectionView didEndDisplayingItem:(nonnull NSCollectionViewItem *)item forRepresentedObjectAtIndexPath:(nonnull NSIndexPath *)indexPath {
}
- (NSInteger) numberOfSectionsInCollectionView:(NSCollectionView *)collectionView {
return (1);
}
- (NSInteger) collectionView:(NSCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return (ar.count);
}
- (NSCollectionViewItem *) collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath
{
ProjectTabLeadersCollectionItem *item = [collectionView makeItemWithIdentifier:@"ProjectTabLeadersCollectionItem" forIndexPath:indexPath];
item->StatNameLabel.stringValue = [ar objectAtIndex:[indexPath item]];
return (item);
// ProjectTabStandingsCollectionItem *item = [collectionView makeItemWithIdentifier:@"ProjectTabStandingsCollectionItem" forIndexPath:indexPath];
// ProjectTeamObject *pto = [standings objectAtIndex:[indexPath item]];
//
// item->StandingsLabel.stringValue = pto.profile.city;
// return (item);
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
@end
The documentation of viewDidMoveToWindow
states
The default implementation does nothing
but [NSCollectionView viewDidMoveToWindow]
is implemented and starts observing firstResponder
of the window. -[ProjectTabLeadersCollection viewDidMoveToWindow]
must call super
.