NSTabView 内嵌的 NSCollectionView 崩溃时的神秘观察者

Mystery observer in crash of NSCollectionView embedded in NSTabView

我在 NSTabView 的选项卡之一中嵌入了 NSCollectionView。 collection 已加载并正确显示,但在切换到任何其他选项卡后,应用程序崩溃并显示以下崩溃日志。崩溃指出无法为关键路径“firstResponder”删除观察者(ProjectTabLeadersCollection,它是我的 NSCollectionView 的 class)。我不确定到底发生了什么,因为我没有明确地为这个选项卡注册任何观察者,所以我假设 AppKit 在幕后做一些事情,以及我在 Interface Builder 或我的初始化代码中的设置不太正确。希望有人能在这里提供一些指导。

有什么想法吗?

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

我的选项卡视图设置如下:

NSCollection 位于名为 Leaders 的选项卡中,连接如下所示:

这是 collection 的 header:

@interface ProjectTabLeadersCollection : NSCollectionView <NSCollectionViewDataSource, NSCollectionViewDelegate> {

    NSMutableArray  *ar;
}
@end

接下来,.m 文件:

#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

viewDidMoveToWindow 的文档指出

The default implementation does nothing

[NSCollectionView viewDidMoveToWindow] 已实施并开始观察 window 的 firstResponder-[ProjectTabLeadersCollection viewDidMoveToWindow] 必须调用 super.