NSOperation 子类中的执行选择器

发布于 2024-12-02 23:32:30 字数 2251 浏览 9 评论 0原文

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

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

我有一个 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];
    }
}

任何帮助表示赞赏!

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南七夏 2024-12-09 23:32:30

您的 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 to performSelector:withObject:afterDelay: will not fire. You commented out a call to performSelectorOnMainThread:.... Did this work?

You probably should be running this on the main thread or running this with performSelector:withObject: (without the afterDelay:). performSelector:withObject: does not require a run loop.

昔梦 2024-12-09 23:32:30

正如 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 使用正确的数据。
感谢您的参与:)

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 from

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

and in the -runCallback:

-(void)runCallback{

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

}

This called theSelector in TheTask with the correct data.
Thanks for participating :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文