3

我正在通過「更多iPhone 3開發」的併發章節中的示例進行工作,並且無法按預期方式在NSOperationQueue上運行KVO。我創建NSOperationQueue並使用觀察其operations陣列:使用KO與NSOperationQueue更改字典值錯誤?

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

當第一NSOperation被添加到隊列中,我希望它被添加到它的底層operations陣列(其iOS的文件說是KVO兼容)因此在更改字典中找到從NSKeyValueChangeKindKeyNSKeyValueChangeInsertion的映射,以及從NSKeyValueChangeNewKey到添加的NSOperation的映射。但我沒有看到任何價值NSKeyValueChangeInsertion

我知道調試器是親和的,而是在有東西複製到這裏有用的興趣,我開始了我的觀察法:

- (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); 

這版畫:

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僅僅是我的NSOperation的子類,它恰當地覆蓋main,而Stalled就是項目名稱。)但請注意,在插入單個操作時調用該方法兩次,並且兩次都使用一種值爲1,即NSKeyValueChangeSetting,而不是NSKeyValueChangeInsertion。此外,newValueoldValue似乎是陣列本身,而不是添加的項目。

任何想法?謝謝!

回答

3

該文檔說-operations是KVO兼容的,但不指定通知的詳細信息。在實踐中,看起來你只是被告知發生了變化,所以必須比較舊的和新的值才能找出插入的內容。

不要忘記,這些通知可以發送給你的任何線程!

+0

插入通知將永遠不會被髮送,因爲該屬性具有NSArray類型(檢查文檔),因此無法插入。 – JeremyP 2011-01-04 09:01:21

-1

NSOperationQueue的operations屬性沒有可變類型(它返回NSArray*)。因此,它不會爲可變數組實現索引對多個合規性方法,因此您將永遠不會看到插入事件,只會看到整個數組的變化事件。

編輯

Shadowmatter造就了一個事實,即實際返回的對象是一個NSMutableArray。但是,這並沒有改變任何事情。首先,Apple's documentation是明確的問題。如果通告某個方法以返回不可變對象,則必須尊重該API。您不能使用isKindOf:來確定它是否真的可變,並且您絕對不能更改它。

API說操作返回類型是不可變的,因此你必須這樣對待它。對於這個問題更重要的是,因爲它不是一個可變集合屬性,所以對於可變數組KVC值不是key value coding compliant。對於可變索引的集合達標,類必須

  • 實現的方法-insertObject:in<Key>AtIndex:-insert<Key>:atIndexes:一個或兩個。
  • 執行方法-removeObjectFrom<Key>AtIndex:-remove<Key>AtIndexes:中的一個或兩個。

(直接從Apple KVC導向截取)

NSOperationQueue類的設計者設計了operations屬性爲不可改變,因此有意忽略,則上述方法。

+0

即使它返回「NSArray」類型,返回值的實際類型也是子類「NSMutableArray」。我已經使用'isKindOf'確認了它。這是不夠的? – shadowmatter 2010-11-19 18:26:05

+0

@shadowmatter:查看編輯我的答案 – JeremyP 2010-11-20 12:43:03

+0

謝謝你的回答,JeremyP!更多的iPhone 3開發書實際上指出,即使返回值是「NSArray」,實際返回的實例是「NSMutableArray」,因此您可以觀察到插入或刪除的元素。我認爲蘋果在某個時候解決了這個問題,以便該課程的行爲符合他們自己的文檔,現在這個例子已經被破壞了。這一切都有道理...再次感謝! – shadowmatter 2010-11-20 18:14:34