使用带有NSOperationQueue的KVO时,更改字典值是否错误?

时间:2010-11-19 04:20:15

标签: iphone multithreading key-value-observing foundation nsoperationqueue

我正在通过“更多iPhone 3开发”的并发章节中的一个示例,并且无法使NSOperationQueue的KVO按预期工作。我创建了一个NSOperationQueue并使用以下方法观察其operations数组:

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似乎是数组本身,而不是添加的项目。

有什么想法吗?谢谢!

2 个答案:

答案 0 :(得分:3)

文档说-operations符合KVO标准,但未指定通知的详细信息。在实践中,似乎只告诉您发生了更改,因此必须比较旧值和新值以找出插入的内容。

不要忘记这些通知可以通过任何线程发送给您!

答案 1 :(得分:-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属性设计为不可变,因此故意省略上述方法。