NSOperation KVO 问题
我使用以下函数在 nsoperationqueue 中的操作完成后通知我的应用程序,以便我可以根据操作结果安排任务。我正在使用:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if([keyPath isEqual:@"isFinished"] && _operation == object)
{
NSLog(@"Our Thread Finished!");
[_operation removeObserver:self forKeyPath:@"isFinished"];
[self performSelectorOnMainThread:@selector(showDialog) withObject:nil waitUntilDone:YES];
}
}
我的问题是,因为分配给这些操作的任务大多是解析数据,如果我尝试点击其他按钮或基本上执行一些导致操作的操作,我会得到以下异常:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<Settings: 0x21b970>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: isFinished
我完全理解,因为我尝试在主线程上做其他事情,因此对主线程的调用:
[self performSelectorOnMainThread:@selector(showDialog) withObject:nil waitUntilDone:YES];
无法执行。但是这个问题的解决方案是什么,因为我希望既允许用户在发出请求后执行任何操作,又在完成分配给操作的任务后执行计划的操作。
真的可能吗?
提前致谢。
I'm using following function to get my application notified after the operation in nsoperationqueue has finished, so that I can schedule the task that's dependent upon the result of the operation. I'm using:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if([keyPath isEqual:@"isFinished"] && _operation == object)
{
NSLog(@"Our Thread Finished!");
[_operation removeObserver:self forKeyPath:@"isFinished"];
[self performSelectorOnMainThread:@selector(showDialog) withObject:nil waitUntilDone:YES];
}
}
My question is since mostly the tasks assigned to these operations are parsing of data if I try to tap some other button or basically do something that results in action, I get the following exception:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<Settings: 0x21b970>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: isFinished
I perfectly understand that since I try doing other things on main thread, because of which the call to main thread:
[self performSelectorOnMainThread:@selector(showDialog) withObject:nil waitUntilDone:YES];
fails to get executed. But what's the solution to this problem as I want both allow user do any action after making a request and also perform the action scheduled after finishing the task assigned to the operation.
Is it really possible?
Thanx in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您需要 Mac OS X 10.6 Snow Leopard 或(我认为)iPhone OS 3.0,则可以完全避免使用 KVO。只需为您想要在主线程上执行的工作创建另一个操作,将其需要遵循的操作添加为依赖项,然后将主线程操作放在主队列上即可:
NSOperation 支持不同队列上的操作之间的依赖关系。只是要注意不要使不同队列上的操作相互依赖,因为这会导致死锁。
If you can require Mac OS X 10.6 Snow Leopard, or (I think) iPhone OS 3.0, you can avoid KVO entirely for this. Just create another operation for the work you want to do on the main thread, add the operation it needs to follow as a dependency, and then put the main-thread operation on the main queue:
NSOperation supports dependencies between operations on different queues. Just be careful not to make operations on different queues mutually dependent, because that will result in deadlock.
您看到此问题的原因是您没有使用
context
指针。当您添加或删除观察者时,传递上下文指针。在您的 observeValueForKeyPath:ofObject:change:context: 中,检查上下文点以确保传递的观察结果属于您。如果没有,请致电 super。可以使用 self 作为上下文点,或者可以采用静态字符串的地址等。
下面是一个示例:
添加观察者:
处理更改通知:
删除观察者:
因为您的代码无法将通知之一传递给
observeValueForKeyPath:ofObject:change:context:
中的 super,所以通知进去了但从未出来。这就是你得到这个例外的原因。不幸的是,IntarWebs 上提供的许多键值观察示例都没有正确执行此操作和/或传递
NULL
作为上下文指针(甚至 Apple 的文档也这样做)。The reason your are seeing this problem is that you are not using the
context
pointer.When you add or remove an observer, pass a context pointer. In your
observeValueForKeyPath:ofObject:change:context:
, check the context point to make sure the observation being passed belongs to you. If not, call super. It's possible to use self as the context point, or you can take the address of a static string, etc.Here is an example:
Adding the observer:
Handling the change notification:
Removing the observer:
Because your code was not able to pass one of the notifications to super in
observeValueForKeyPath:ofObject:change:context:
, that notification went in but never came out. This is why you got that exception.It unfortunate that many of the Key-Value Observing examples available on The IntarWebs do not do this correctly and/or pass
NULL
as the context pointer (even Apple's documentation does this).