performSelector in NSOperation subclass

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 (<strong>TheEngine</strong>) which is abstract by convention and must be extended to implement the function -main, to include the body of code to execute.

<strong>TheEngine</strong> 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:

<strong>aViewController</strong> fires up an extension of <strong>TheEngine</strong> - lets say <strong>TheTask</strong> 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!

Answer1:

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.

Answer2:

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 <strong>TheTask</strong> and an exception was thrown as <strong>TheTask</strong> 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 <strong>TheTask</strong> with the correct data. Thanks for participating :)

人吐槽 人点赞

Recommend

Comment

用户名: 密码:
验证码: 匿名发表

你可以使用这些语言

查看评论:performSelector in NSOperation subclass