将 KVO 与 NSOperationQueue 一起使用时更改字典值错误?

发布于 2024-10-03 19:14:44 字数 2075 浏览 10 评论 0 原文

我正在研究“更多 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 添加到队列中时,我希望将其添加到其底层的操作数组(iOS 文档称其符合 KVO 标准),因此在更改字典中查找从 NSKeyValueChangeKindKey 到 NSKeyValueChangeInsertion 的映射>,以及从 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 只是项目名称。)但请注意,该方法在插入单个操作时被调用两次,并且两次都使用kind 值 1,是 NSKeyValueChangeSetting,而不是 NSKeyValueChangeInsertion。此外,newValue 和oldValue 似乎是数组本身,而不是添加的项目。

有什么想法吗?谢谢!

I was working through an example in the concurrency chapter of "More iPhone 3 Development," and can't get KVO on an NSOperationQueue working as expected. I create an NSOperationQueue and observe its operations array using:

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

When the first NSOperation is added to the queue, I expect it to be added to its underlying operations array (which the iOS documentation says is KVO-compliant) and hence, in the change dictionary, to find a mapping from NSKeyValueChangeKindKey to NSKeyValueChangeInsertion, along with a mapping from NSKeyValueChangeNewKey to the added NSOperation. But I wasn't seeing any kind of value NSKeyValueChangeInsertion.

I know the debugger is pro and all, but in the interest of having something useful to copy here, I started my observer method with:

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

And that prints:

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 is simply my subclass of NSOperation that overrides main appropriately, and Stalled is simply the project name.) But note that the method is called twice upon inserting a single operation, and both times with a kind value of 1, which is NSKeyValueChangeSetting, not NSKeyValueChangeInsertion. Additionally, newValue and oldValue seem to be the array itself, not the item added.

Any ideas? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

久夏青 2024-10-10 19:14:44

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

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

The docs say -operations is KVO-compliant, but don't specify to what detail the notifications will be. In practice, it seems you are only told that a change has occurred, so would have to compare the old and new values to find out what was inserted.

Don't forget that these notifications can be sent to you on any thread!

歌枕肩 2024-10-10 19:14:44

NSOperationQueue 的操作属性没有可变类型(它返回NSArray*)。因此,它不会实现可变数组的索引多合规方法,因此您永远不会看到插入事件,只能看到整个数组的更改事件。

编辑

Shadowmatter提出了这样一个事实:实际返回的对象是一个NSMutableArray。然而,这并没有改变任何事情。首先, Apple 的文档对此问题有明确说明。如果某个方法被宣传为返回不可变对象,则必须遵守 API。您不得使用 isKindOf: 来确定它是否确实可变,并且绝对不能更改它。

API 表示操作返回类型是不可变的,因此您必须如此对待它。对于这个问题更重要的是,因为它不是可变集合属性,所以它不是 键值编码符合可变数组 KVC 值的。对于可变索引集合合规性,该类必须

  • 实现 -insertObject:inAtIndex:-insert:atIndexes: 方法之一或两者。
  • 实现 -removeObjectFromAtIndex:-removeAtIndexes: 方法之一或两者。

(直接摘自Apple KVC指南)

NSOperationQueue类的设计者将operations属性设计为不可变的,因此故意省略了上述方法。

The operations property of NSOperationQueue does not have a mutable type (it returns NSArray*). It therefore does not implement the indexed to-many compliance methods for mutable arrays so you'll never see the insert events, only the change event for the whole array.

Edit

Shadowmatter has brought up the fact that the actually returned object is an NSMutableArray. This does not, however, change anything. Firstly, Apple's documentation is clear on the issue. If a method is advertised to return an immutable object, you must respect the API. You must not use isKindOf: to find out if it is really mutable and you must definitely not change it.

The API says the operations return type is immutable and you must therefore treat it as such. More importantly for this question, as it's not a mutable collection property, it is not key value coding compliant for the mutable array KVC values. For mutable indexed collection compliance, the class has to

  • Implement one or both of the methods -insertObject:in<Key>AtIndex: or -insert<Key>:atIndexes:.
  • Implement one or both of the methods -removeObjectFrom<Key>AtIndex: or -remove<Key>AtIndexes:.

(taken directly from the Apple KVC guide)

The designer of the NSOperationQueue class designed the operations property as immutable and therefore deliberately ommitted the above methods.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文