NSOperation子类中的performSelector

时间:2011-09-01 23:39:32

标签: objective-c key-value-observing nsoperation nsoperationqueue performselector

我无法在网络上的任何其他地方找到答案,所以任何帮助都会受到赞赏。

我想创建一个系统,我可以检索NSOperation任务的结果,我理解不能通过NSInvocation这样的具体子类来完成。

我有一个NSOperation子类( TheEngine ),它是按惯例抽象的,必须扩展才能实现函数-main,以包含要执行的代码体。

TheEngine 包含以下初始化函数,其作用只是注意选择器所属的theSelectortheObject。它还为属性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];
    }
}

任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:1)

您的NSOperation可能正在后台线程上运行。如果该线程消失,或者该线程无法泵送其运行循环,则您对performSelector:withObject:afterDelay:的调用将不会触发。你注释了对performSelectorOnMainThread:...的电话。这有用吗?

你可能应该在主线程上运行它,或者使用performSelector:withObject:(没有afterDelay:)运行它。 performSelector:withObject:不需要运行循环。

答案 1 :(得分:0)

正如Rob建议的那样,代码在后台线程中运行,调用observeValueForKeyPath:ofObject:change:context:

也是如此

我最初更改了代码,以便使用[self performSelectorOnMainThread:@selector(runCallback) withObject:nil waitUntilDone:NO];在主线程上触发选择器。

但是在这种情况下,主线程变成了 TheTask ,并且因为 TheTask 不拥有theSelector而引发了异常。为了解决这个问题,我创建了一个额外的函数-runCallback并从

中解除了它
-(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:@selector(runCallback) withObject:nil waitUntilDone:NO];

        //[self performSelectorOnMainThread:self.selectorToCallWhenFinished withObject:self.resultData waitUntilDone:NO];
        //[self.selectorsParentObject performSelector:@selector(selectorToCallWhenFinished) withObject:self.resultData afterDelay:0];
    }
}

-runCallback

-(void)runCallback{

    [self.selectorsParentObject performSelector:self.selectorToCallWhenFinished withObject:self.resultData afterDelay:0];

}

这会在 TheTask 中调用theSelector并使用正确的数据。 感谢参与:)