将自己作为观察者添加到数组中,而不是绑定到 NSArrayController?

发布于 2024-09-13 09:17:42 字数 4460 浏览 5 评论 0原文

我有一个名为 AppController 的类,其中包含一个名为 peoplePerson 对象的可变数组。每个人只有一个 NSString 和一个 float。

我还有一个 NSArrayController,其 contentArray 绑定到 AppController 中的 people 数组。然后,我将表视图绑定到数组控制器,以显示所有人员对象的列表。

在我的 AppController 类中,我尝试注册为 people 数组的观察者以添加撤消支持。我是这样做的:

@implementation AppController

@synthesize people;

- (id)init
{
    self = [super init];
    if (self != nil) {
        people = [[NSMutableArray alloc] init];
        undoManager = [[NSUndoManager alloc] init];
        [self addObserver:self 
               forKeyPath:@"people" 
                  options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld 
                  context:NULL];
    }
    return self;
}

- (void)undo:(id)sender
{
    [undoManager undo];
}

- (void)redo:(id)sender
{
    [undoManager redo];
}

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context
{
    int kindOfChange = [[change objectForKey:NSKeyValueChangeKindKey] intValue];
    int index = [[change objectForKey:NSKeyValueChangeIndexesKey] firstIndex];

    Person *p;

    if (kindOfChange == NSKeyValueChangeInsertion) {
        p = [change objectForKey:NSKeyValueChangeNewKey];
        [[undoManager prepareWithInvocationTarget:self] removePersonAtIndex:index];
    } else {
        p = [change objectForKey:NSKeyValueChangeOldKey];
        [[undoManager prepareWithInvocationTarget:self] addPerson:p atIndex:index];
    }
}

- (void)addPerson:(Person *)person atIndex:(int)index
{
    [[self mutableArrayValueForKey:@"people"] addObject:person];
}

- (void)removePersonAtIndex:(int)index
{
    [[self mutableArrayValueForKey:@"people"] removeObjectAtIndex:index];
}

@end

使用此代码,我可以成功添加一个人员对象,然后撤消它。但是,我无法撤消删除人员对象的操作。当我撤消删除操作时,我总是遇到此异常:

[<NSCFArray 0x3009a0> addObserver:forKeyPath:options:context:] is not supported.  Key path: personName

不过,似乎我不是唯一的: http://www.cocoabuilder.com/archive/cocoa/84489-modifying-the-array-of-an-nsarraycontroller.html#84496 有什么

想法吗?

更新:

这是回溯:

#0  0x7fff8161b41e in -[NSArray(NSKeyValueObserverRegistration) addObserver:forKeyPath:options:context:]
#1  0x7fff8822fc47 in -[_NSModelObservingTracker _registerOrUnregister:observerNotificationsForModelObject:]
#2  0x7fff883b2bb9 in -[_NSModelObservingTracker startObservingModelObjectAtReferenceIndex:]
#3  0x7fff883acc41 in -[_NSModelObservingTracker setObservingToModelObjectsRange:]
#4  0x7fff883aca5a in -[NSTableBinder tableView:updateVisibleRowInformation:]
#5  0x7fff883ac98e in -[_NSBindingAdaptor tableView:updateVisibleRowInformation:]
#6  0x7fff882b4c7b in -[NSTableView drawRect:]
#7  0x7fff882ab081 in -[NSView _drawRect:clip:]
#8  0x7fff882a9cf4 in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:]
#9  0x7fff882aa05e in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:]
#10 0x7fff882aa05e in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:]
#11 0x7fff882a83c6 in -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]
#12 0x7fff882a9292 in -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]
#13 0x7fff882a9292 in -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]
#14 0x7fff882a7ee8 in -[NSThemeFrame _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]
#15 0x7fff882a479a in -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:]
#16 0x7fff8821dff6 in -[NSView displayIfNeeded]
#17 0x7fff88218ea2 in _handleWindowNeedsDisplay
#18 0x7fff81da9077 in __CFRunLoopDoObservers
#19 0x7fff81d84ef4 in __CFRunLoopRun
#20 0x7fff81d8484f in CFRunLoopRunSpecific
#21 0x7fff8836ab31 in _NSUnhighlightCarbonMenu
#22 0x7fff8834d0c1 in -[NSMenu performKeyEquivalent:]
#23 0x7fff8834be69 in -[NSApplication _handleKeyEquivalent:]
#24 0x7fff8821caa1 in -[NSApplication sendEvent:]
#25 0x7fff881b3922 in -[NSApplication run]
#26 0x7fff881ac5f8 in NSApplicationMain
#27 0x100001469 in main at main.m:13

I have class called AppController which contains a mutable array of Person objects called people. Each person simply has an NSString and a float.

I also have an NSArrayController whose contentArray is bound to the people array in AppController. Then I have the usual setup of a table view bound to the array controller to show a list of all the person objects.

In my AppController class, I tried to register as an observer of the people array to add undo support. Here's how I do it:

@implementation AppController

@synthesize people;

- (id)init
{
    self = [super init];
    if (self != nil) {
        people = [[NSMutableArray alloc] init];
        undoManager = [[NSUndoManager alloc] init];
        [self addObserver:self 
               forKeyPath:@"people" 
                  options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld 
                  context:NULL];
    }
    return self;
}

- (void)undo:(id)sender
{
    [undoManager undo];
}

- (void)redo:(id)sender
{
    [undoManager redo];
}

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context
{
    int kindOfChange = [[change objectForKey:NSKeyValueChangeKindKey] intValue];
    int index = [[change objectForKey:NSKeyValueChangeIndexesKey] firstIndex];

    Person *p;

    if (kindOfChange == NSKeyValueChangeInsertion) {
        p = [change objectForKey:NSKeyValueChangeNewKey];
        [[undoManager prepareWithInvocationTarget:self] removePersonAtIndex:index];
    } else {
        p = [change objectForKey:NSKeyValueChangeOldKey];
        [[undoManager prepareWithInvocationTarget:self] addPerson:p atIndex:index];
    }
}

- (void)addPerson:(Person *)person atIndex:(int)index
{
    [[self mutableArrayValueForKey:@"people"] addObject:person];
}

- (void)removePersonAtIndex:(int)index
{
    [[self mutableArrayValueForKey:@"people"] removeObjectAtIndex:index];
}

@end

With this code, I can successfully add a person object and then undo it. I cannot, however, undo deleting a person object. I always get this exception when I undo a delete operation:

[<NSCFArray 0x3009a0> addObserver:forKeyPath:options:context:] is not supported.  Key path: personName

It seems like I'm not the only one, though: http://www.cocoabuilder.com/archive/cocoa/84489-modifying-the-array-of-an-nsarraycontroller.html#84496

Any ideas?

UPDATE:

Here's the backtrace:

#0  0x7fff8161b41e in -[NSArray(NSKeyValueObserverRegistration) addObserver:forKeyPath:options:context:]
#1  0x7fff8822fc47 in -[_NSModelObservingTracker _registerOrUnregister:observerNotificationsForModelObject:]
#2  0x7fff883b2bb9 in -[_NSModelObservingTracker startObservingModelObjectAtReferenceIndex:]
#3  0x7fff883acc41 in -[_NSModelObservingTracker setObservingToModelObjectsRange:]
#4  0x7fff883aca5a in -[NSTableBinder tableView:updateVisibleRowInformation:]
#5  0x7fff883ac98e in -[_NSBindingAdaptor tableView:updateVisibleRowInformation:]
#6  0x7fff882b4c7b in -[NSTableView drawRect:]
#7  0x7fff882ab081 in -[NSView _drawRect:clip:]
#8  0x7fff882a9cf4 in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:]
#9  0x7fff882aa05e in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:]
#10 0x7fff882aa05e in -[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:]
#11 0x7fff882a83c6 in -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]
#12 0x7fff882a9292 in -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]
#13 0x7fff882a9292 in -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]
#14 0x7fff882a7ee8 in -[NSThemeFrame _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:]
#15 0x7fff882a479a in -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:]
#16 0x7fff8821dff6 in -[NSView displayIfNeeded]
#17 0x7fff88218ea2 in _handleWindowNeedsDisplay
#18 0x7fff81da9077 in __CFRunLoopDoObservers
#19 0x7fff81d84ef4 in __CFRunLoopRun
#20 0x7fff81d8484f in CFRunLoopRunSpecific
#21 0x7fff8836ab31 in _NSUnhighlightCarbonMenu
#22 0x7fff8834d0c1 in -[NSMenu performKeyEquivalent:]
#23 0x7fff8834be69 in -[NSApplication _handleKeyEquivalent:]
#24 0x7fff8821caa1 in -[NSApplication sendEvent:]
#25 0x7fff881b3922 in -[NSApplication run]
#26 0x7fff881ac5f8 in NSApplicationMain
#27 0x100001469 in main at main.m:13

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

温柔戏命师 2024-09-20 09:17:42

发生的情况是 [change objectForKey: NSKeyValueChangeNewKey] 返回 NSArray *,而不是 Person *。您应该对返回的数组调用 -lastObject 以获取实际的 Person 对象(假设该数组仅包含一个对象)。

What's happening is that [change objectForKey: NSKeyValueChangeNewKey] returns NSArray *, not Person *. You should call -lastObject on the array returned to get the actual Person object (assuming that the array contains only one object).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文