Valore-chiave: osservazione di una relazione to-many in Cocoa

Sto cercando di ottenere il valore-chiave-osservazione per funzionare per un NSMutableArray. Di seguito è riportato il file .h per MyObservee, la class osservata:

@interface MyObservee : NSObject { @private int someValue; @private NSMutableArray *someArray; } @property (readwrite,assign) int someValue; - (NSMutableArray *)someArray; @end 

La class MyObserver implementa observValueForKeyPath: ofObject: change: context :. Ecco come aggiungo l’osservatore:

 MyObservee *moe = [[MyObservee alloc] init]; MyObserver *mobs = [[MyObserver alloc] init]; [moe addObserver:mobs forKeyPath:@"someArray" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL]; [moe.someArray addObject:@"hi there"]; 

Come mai il messaggio addObject: non viene triggersto come una modifica al percorso della chiave someArray? Ho la sensazione che ci sia qualcosa che non capisco completamente qui.

È necessario implementare gli accessor di array indicizzati come definito nella guida alla programmazione di KVC . Quindi è necessario utilizzare quegli accessor per accedere all’array e il trigger KVO funzionerà. Puoi anche chiamare -mutableArrayValueForKey: e usare quell’array su addObject: e tale e a sua volta chiamerà i metodi accessor e si verificherà anche l’triggerszione KVO. Ci sono anche set accessors da usare per NSSets, vedi qui e qui .

Esempio:

 @interface MyClass : NSObject { NSMutableArray *_orders; } @property(retain) NSMutableArray *orders; - (NSUInteger)countOfOrders; - (id)objectInOrdersAtIndex:(NSUInteger)index; - (void)insertObject:(id)obj inOrdersAtIndex:(NSUInteger)index; - (void)removeObjectFromOrdersAtIndex:(NSUInteger)index; - (void)replaceObjectInOrdersAtIndex:(NSUInteger)index withObject:(id)obj; @end 

Sfortunatamente, le classi NSArray sono note come conformi al KVO. Sono compatibili con KVC, ma non puoi osservarli direttamente come stai cercando di fare qui. Il modo più semplice per ottenere questa funzionalità sarebbe utilizzare un controller NSArray. Il controller NSArray è conforms a KVO e ti avviserà quando gli articoli vengono aggiunti o rimossi. Nel tuo esempio, il tuo osservatore verrebbe informato se in realtà hai modificato la matrice stessa. Ad esempio, se hai fatto qualcosa del genere:

 [moe setSomeArray:[NSMutableArray array]]; 

Probabilmente non è quello che volevi tu 🙂 Proprio come una parte, NSDictionary è in realtà KVO in modo che tu possa usarlo, se hai scelto. Oppure potresti scrivere una sottoclass wrapper di NSMutableArray che crea solo un vero array mutabile come backing store ma solo inoltra su tutti i messaggi ad esso tranne addObject e removeObject che potresti sovrascrivere per triggersre le notifiche.

Perché stai passando il tuo array privato a un altro object? Non è così privato quando lasci che gli altri oggetti lo gestiscano.

Come s-bug ha detto, è necessario implementare gli accessor e utilizzare mutableArrayValueForKey: per modificare la proprietà. Aggiungo che non dovresti esporre quell’array privato a tutti – il someArray metodo di un array dovrebbe restituire una copia immutabile dell’array.

Inoltre, richiamo la tua attenzione sul commento di Jason Coco sulla risposta di s-bug. Per parafrasarlo, dovresti probabilmente usare un NSArrayController come ulteriore passaggio di separazione tra myObservee e myObserver . Questo è un ottimo suggerimento e, se non hai una ragione specifica per osservare direttamente la proprietà, dovresti prenderla. (Tra i vantaggi è che puoi utilizzare Bindings per connettere le viste al nuovo controller di array.)