3

Ich arbeitete durch ein Beispiel im Nebenläufigkeitskapitel von "Mehr iPhone 3 Entwicklung" und kann KVO auf NSOperationQueue nicht wie erwartet funktionieren. Ich erstelle eine NSOperationQueue und beobachten seine operations Array:Ändern Sie die Wörterbuchwerte falsch, wenn Sie KVO mit NSOperationQueue verwenden?

NSOperationQueue *newQueue = [[NSOperationQueue alloc] init]; 
self.queue = newQueue; 
[newQueue release]; 
[queue addObserver:self 
     forKeyPath:@"operations" 
      options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) 
      context:NULL]; 

Wenn die erste NSOperation der Warteschlange hinzugefügt wird, erwarte ich ihn auf sein operations Array hinzugefügt werden (die die iOS-Dokumentation sagt, ist KVO-konform) und daher in dem Änderungswörterbuch eine Zuordnung von NSKeyValueChangeKindKey zu NSKeyValueChangeInsertion zusammen mit einer Zuordnung von NSKeyValueChangeNewKey zu der hinzugefügten NSOperation zu finden. Aber ich sah keinen Wert .

weiß, dass ich die Debugger ist Pro und alle, aber im Interesse der hier zu kopieren, etwas Nützliches zu haben, begann ich meine Beobachter Methode mit:

- (void) observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context { 
    NSNumber *kind = [change objectForKey:NSKeyValueChangeKindKey]; 
    NSObject *newValue = [change objectForKey:NSKeyValueChangeNewKey]; 
    NSObject *oldValue = [change objectForKey:NSKeyValueChangeOldKey]; 
    NSIndexSet *indexes = [change objectForKey:NSKeyValueChangeIndexesKey]; 
    NSLog(@"kind=%d, newValue=%@, oldValue=%@, indexes=%@", 
     [kind integerValue], newValue, oldValue, indexes); 

Und den Druck:

2010-11-18 20:01:56.249 Stalled[2692:6f07] kind=1, newValue=(
    "<SquareRootOperation: 0x5f51b40>" 
), oldValue=(
), indexes=(null) 

2010-11-18 20:01:56.250 Stalled[2692:6f07] kind=1, newValue=(
    "<SquareRootOperation: 0x5f51b40>" 
), oldValue=(
    "<SquareRootOperation: 0x5f51b40>" 
), indexes=(null) 

(SquareRootOperation ist einfach meine Unterklasse von NSOperation, die main entsprechend übersteuert, und Stalled ist einfach der Projektname.) Beachten Sie jedoch, dass die Methode zweimal beim Einfügen einer einzelnen Operation und beide Male mit einer Art aufgerufen wird Wert von 1, der NSKeyValueChangeSetting ist, nicht NSKeyValueChangeInsertion. Außerdem scheinen newValue und oldValue das Array selbst zu sein, nicht das hinzugefügte Element.

Irgendwelche Ideen? Vielen Dank!

Antwort

3

Die Dokumente sagen -operations ist KVO-konform, aber nicht angeben, in welchem ​​Detail die Benachrichtigungen sein werden. In der Praxis scheint es, dass Ihnen nur gesagt wird, dass eine Änderung stattgefunden hat, also müssten Sie die alten und neuen Werte vergleichen, um herauszufinden, was eingefügt wurde.

Vergessen Sie nicht, dass diese Benachrichtigungen zu jedem Thread gesendet werden können!

+0

Die Einfügebenachrichtigung wird niemals gesendet, da die Eigenschaft den Typ NSArray aufweist (siehe Dokumentation) und daher nicht eingefügt werden kann. – JeremyP

-1

Die Operationseigenschaft von NSOperationQueue hat keinen veränderbaren Typ (es gibt NSArray* zurück). Daher implementiert es die indizierten Zu-Viele-Compliance-Methoden für veränderbare Arrays nicht, so dass Sie niemals die Einfügungsereignisse, sondern nur das Änderungsereignis für das gesamte Array sehen werden.

bearbeiten

Shadowmatter hat die Tatsache, dass die tatsächlich zurückgegebene Objekt ist ein NSMutableArray gebracht. Dies ändert jedoch nichts. Erstens, Apple's documentation ist klar in der Frage. Wenn eine Methode angekündigt wird, ein unveränderliches Objekt zurückzugeben, müssen Sie die API respektieren. Sie dürfen nicht verwenden, um herauszufinden, ob es wirklich veränderbar ist, und Sie müssen es definitiv nicht ändern.

Die API besagt, dass der Rückgabetyp operations unveränderlich ist und Sie ihn daher als solchen behandeln müssen. Wichtiger für diese Frage ist, dass es sich nicht um eine veränderbare Auflistungseigenschaft handelt, sondern um key value coding compliant für die KVC-Werte des veränderbaren Arrays. Für wandelbar indizierte Compliance, hat die Klasse

  • eine oder beide der Methoden -insertObject:in<Key>AtIndex: oder -insert<Key>:atIndexes: implementieren.
  • Implementieren Sie eine oder beide der Methoden -removeObjectFrom<Key>AtIndex: oder -remove<Key>AtIndexes:.

Der Designer der NSOperationQueue Klasse (direkt aus dem Apple KVC Führer genommen) entwickelt, um die operations Eigenschaft als unveränderlich und daher bewusst die oben genannten Methoden weggelassen.

+0

Obwohl der Typ 'NSArray' zurückgegeben wird, ist der tatsächliche Typ des zurückgegebenen Werts die Unterklasse' NSMutableArray'. Ich habe es mit 'isKindOf' bestätigt. Ist das nicht genug? – shadowmatter

+0

@Shadowmatter: Siehe die Bearbeitung meiner Antwort – JeremyP

+0

Danke für die Antwort, JeremyP! Das More iPhone 3 Development Buch wies tatsächlich darauf hin, dass, obwohl der Rückgabewert "NSArray" war, die tatsächlich zurückgegebene Instanz "NSMutableArray" war und Sie Elemente beobachten konnten, die eingefügt oder entfernt wurden. Ich nehme an, dass Apple dies irgendwann behoben hat, so dass das Verhalten der Klasse ihrer eigenen Dokumentation entsprach, und nun ist das Beispiel gebrochen. Es macht alles jetzt Sinn ... Danke nochmal! – shadowmatter