2

我在网上的其他任何地方都找不到答案,因此我们将不胜感激。

我打算创建一个系统,以便我可以检索 NSOperation 任务的结果,据我所知,这不能通过具体的子类(例如 NSInvocation)来完成。

我有一个 NSOperation 子类(TheEngine),它按约定是抽象的,必须扩展以实现该功能-main,以包含要执行的代码主体。

TheEngine包含以下初始化函数,其工作只是注意theSelectortheObject选择器所属。它还为该属性注册了一个 KV 观察者isFinished

-(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];
    }
}

任何帮助表示赞赏!

4

2 回答 2

1

NSOperation可能在后台线程上运行。如果该线程消失,或者如果该线程无法抽出其运行循环,那么您的调用performSelector:withObject:afterDelay:将不会触发。您注释掉了对 的调用performSelectorOnMainThread:...。这行得通吗?

您可能应该在主线程上运行它或使用performSelector:withObject:(不带afterDelay:)运行它。performSelector:withObject:不需要运行循环。

于 2011-09-01T23:50:15.650 回答
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];

}

这用正确的数据调用theSelectorTheTask 。感谢参与:)

于 2011-09-02T17:01:00.823 回答