NSOperation 子类中的执行选择器
我在网上其他地方找不到答案,因此我们将不胜感激。
我正在创建一个系统,通过该系统我可以检索 NSOperation 任务的结果,据我所知,这不能通过具体的子类(例如 NSInitation)来完成。
我有一个 NSOperation 子类 (TheEngine),按照惯例它是抽象的,必须扩展以实现函数 -main
,以包含要执行的代码主体。
TheEngine 包含以下初始化函数,其作用只是记录选择器所属的 theSelector
和 theObject
。它还为属性 isFinished
注册了一个 KV 观察者:
-(id)initWithCallbackSelector:(SEL)theSelector inObject:(id)theObject
在我的 observeValueForKeyPath:ofObject:change:context:
函数中,我想像这样调用回调函数:
NSLog(@"Some debug text to ensure this function is being called", nil);
[theObject performSelector:theSelector withObject:someData afterDelay:0];
整个过程像这样:
aViewController 启动 TheEngine 的扩展 - 让我们通过调用以下代码并将其添加到操作队列来表示 TheTask。
TheTask* TT = [[TheTask alloc] initWithCallbackSelector:
@selector(resultHandler:) inObject:theObject];
一切似乎都按预期运行,没有任何错误或异常。但是,当执行到达 observeValueForKeyPath:ofObject:change:context: 时,回调实际上并未被调用。我是 Obj-C 的新手,所以我不完全确定我对这种类型线程的理解是否正确。
这是完整的代码:
-(id)initWithCallbackSelector:(SEL)theSelector inObject:(id)theObject{
if([self init]){
self.selectorsParentObject = theObject;
self.selectorToCallWhenFinished = theSelector;
[self addObserver:self forKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew context:NULL];
return self;
}
return nil;
}
-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)theObject change:(NSDictionary*)theChange context:(void*)theContext{
if([keyPath isEqualToString:@"isFinished"]){
NSLog(@"activity is finished with change: %@", theChange);
NSLog(@"target object: %@", self.selectorsParentObject);
NSLog(@"target selector: %@", NSStringFromSelector(self.selectorToCallWhenFinished));
//[self performSelectorOnMainThread:self.selectorToCallWhenFinished withObject:self.resultData waitUntilDone:NO];
[self.selectorsParentObject performSelector:@selector(selectorToCallWhenFinished) withObject:self.resultData afterDelay:0];
}
}
任何帮助表示赞赏!
I couldn't find an answer anywhere else on the net so any help would be appreciated.
I am tying to create a system whereby I can retrieve the results of an NSOperation task, which I understand cannot be done by concrete subclasses such as NSInvocation.
I have an NSOperation subclass (TheEngine) which is abstract by convention and must be extended to implement the function -main
, to include the body of code to execute.
TheEngine contains the following initialisation function whose job is simply to note theSelector
and theObject
the selector belongs to. It also registers a KV observer for the property isFinished
:
-(id)initWithCallbackSelector:(SEL)theSelector inObject:(id)theObject
In my observeValueForKeyPath:ofObject:change:context:
function I would like to call the callback function like so:
NSLog(@"Some debug text to ensure this function is being called", nil);
[theObject performSelector:theSelector withObject:someData afterDelay:0];
The whole process goes like this:
aViewController fires up an extension of TheEngine - lets say TheTask by calling the following and adding it to an operations queue.
TheTask* TT = [[TheTask alloc] initWithCallbackSelector:
@selector(resultHandler:) inObject:theObject];
Everything seems to run as expected without any errors or exceptions at all. But when execution reaches the observeValueForKeyPath:ofObject:change:context:
the callback is not actually called. I'm new to Obj-C, so I'm not entirely sure if my understanding of this type of threading is correct.
Here is the entire code:
-(id)initWithCallbackSelector:(SEL)theSelector inObject:(id)theObject{
if([self init]){
self.selectorsParentObject = theObject;
self.selectorToCallWhenFinished = theSelector;
[self addObserver:self forKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew context:NULL];
return self;
}
return nil;
}
-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)theObject change:(NSDictionary*)theChange context:(void*)theContext{
if([keyPath isEqualToString:@"isFinished"]){
NSLog(@"activity is finished with change: %@", theChange);
NSLog(@"target object: %@", self.selectorsParentObject);
NSLog(@"target selector: %@", NSStringFromSelector(self.selectorToCallWhenFinished));
//[self performSelectorOnMainThread:self.selectorToCallWhenFinished withObject:self.resultData waitUntilDone:NO];
[self.selectorsParentObject performSelector:@selector(selectorToCallWhenFinished) withObject:self.resultData afterDelay:0];
}
}
Any help appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的 NSOperation 可能在后台线程上运行。如果该线程消失,或者该线程无法启动其运行循环,那么您对performSelector:withObject:afterDelay:的调用将不会触发。您注释掉了对
performSelectorOnMainThread:...
的调用。这有效吗?您可能应该在主线程上运行它,或者使用
performSelector:withObject:
(不带afterDelay:
)运行它。performSelector:withObject:
不需要运行循环。Your
NSOperation
is likely running on a background thread. If that thread goes away, or if that thread fails to pump its run loop, then your call toperformSelector:withObject:afterDelay:
will not fire. You commented out a call toperformSelectorOnMainThread:...
. Did this work?You probably should be running this on the main thread or running this with
performSelector:withObject:
(without theafterDelay:
).performSelector:withObject:
does not require a run loop.正如 Rob 所建议的,代码是在后台线程中运行的,调用时也是如此。observeValueForKeyPath:ofObject:change:context:
我最初更改了代码,以便在主线程上使用 <代码>[self PerformSelectorOnMainThread:@selector(runCallback) withObject:nil waitUntilDone:NO];。
但在本例中,主线程是 TheTask,并且由于 TheTask 不拥有
theSelector
,因此引发了异常。为了纠正这个问题,我创建了一个额外的函数-runCallback
并从
-runCallback
中触发它:这在 TheTask 中称为
theSelector
使用正确的数据。感谢您的参与:)
As Rob suggested, the code was running in a background thread, as was the call
observeValueForKeyPath:ofObject:change:context:
I had initially changed the code so that the selector was fired on the main thread with
[self performSelectorOnMainThread:@selector(runCallback) withObject:nil waitUntilDone:NO];
.But in this case the main thread turns out to be the TheTask and an exception was thrown as TheTask does not own
theSelector
. To correct this, I created an extra function-runCallback
and fired it fromand in the
-runCallback
:This called
theSelector
in TheTask with the correct data.Thanks for participating :)