Añadiendo a sí mismo como un observador a un array de una NSArrayController está obligado a?
-
26-09-2019 - |
Pregunta
Tengo clase llamada AppController
que contiene un array mutable de Person
objetos llamados people
. Cada persona tiene simplemente una NSString y un flotador.
I también tienen un NSArrayController
cuya contentArray
está unido a la matriz people
en AppController. Entonces tengo la configuración habitual de una vista de tabla unida a la controladora de la matriz para mostrar una lista de todos los objetos persona.
En mi clase AppController, traté de registrarse como un observador de la matriz a la gente a añadir deshacer apoyo. Así es como lo hago:
@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
Con este código, que puede agregar correctamente un objeto persona y luego deshacerlo. No puedo, sin embargo, deshacer la eliminación de un objeto persona. Siempre tengo esta excepción cuando puedo deshacer una operación de eliminación:
[<NSCFArray 0x3009a0> addObserver:forKeyPath:options:context:] is not supported. Key path: personName
Parece que no soy el único, sin embargo: http://www.cocoabuilder.com/archive/cocoa/84489-modifying-the-array-of-an-nsarraycontroller.html#84496
¿Alguna idea?
ACTUALIZACIÓN:
Aquí está la traza inversa:
#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
Solución
Lo que pasa es que los retornos [change objectForKey: NSKeyValueChangeNewKey]
NSArray *
, no Person *
. Debe llamar -lastObject
en la matriz devuelta para obtener el objeto persona real (suponiendo que la matriz contiene sólo un objeto).