performSelector in NSOperation subclass

[亡魂溺海] 提交于 2019-12-24 00:52:35

问题


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!


回答1:


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.




回答2:


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 :)



来源:https://stackoverflow.com/questions/7277839/performselector-in-nsoperation-subclass

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!