将 KVO 与 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
添加到队列中时,我希望将其添加到其底层的操作数组(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 似乎是数组本身,而不是添加的项目。
有什么想法吗?谢谢!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
文档说
-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!
NSOperationQueue 的操作属性没有可变类型(它返回
NSArray*
)。因此,它不会实现可变数组的索引多合规方法,因此您永远不会看到插入事件,只能看到整个数组的更改事件。编辑
Shadowmatter提出了这样一个事实:实际返回的对象是一个
NSMutableArray
。然而,这并没有改变任何事情。首先, Apple 的文档对此问题有明确说明。如果某个方法被宣传为返回不可变对象,则必须遵守 API。您不得使用isKindOf:
来确定它是否确实可变,并且绝对不能更改它。API 表示操作返回类型是不可变的,因此您必须如此对待它。对于这个问题更重要的是,因为它不是可变集合属性,所以它不是 键值编码符合可变数组 KVC 值的。对于可变索引集合合规性,该类必须
(直接摘自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 useisKindOf:
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
(taken directly from the Apple KVC guide)
The designer of the
NSOperationQueue
class designed theoperations
property as immutable and therefore deliberately ommitted the above methods.