16784

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

  • python kivy AttributeError: 'super' object has no attribute '__getattr__'
  • Kivy Digital Clock Issues
  • Vuejs and Vue.set(), update an Key/Value array
  • Scala: aggregate column based file
  • Kivy hyperlink in kv file
  • Memory management related to void* context in Cocoa
  • Multiple CoGroupByKey with same key apache beam
  • Kivy - Add an icon to tab buttons
  • Progress Bar in Cocoa
  • ndb get & get_or_insert how to use ? (alway raise Exception)
  • How to do a cartesian product of two PCollections in Dataflow?
  • Docker - oracle.kv.FaultException: Could not contact any RepNode
  • Dataflow GroupBy -> multiple outputs based on keys
  • ValueProvider type parameters not getting honored at the template execution time
  • performSelector in NSOperation subclass
  • JavaScript get page coordinates of closest clicked character
  • select only 1st level of nested elements
  • How do I interpolate a line number from __LINE__ into the name of a test in Perl?
  • Get highlight text in current window and send it in a popup
  • Elasticsearch script query involving root and nested values
  • Why use database factory in asp.net mvc?
  • How do I configure context broker accept post requests from my remote sensor?
  • Javascript Callbacks with Object constructor
  • Traverse Array and Display in markup
  • Transpose CSV data with awk (pivot transformation)
  • Why can't I rebase on to an ancestor of source changesets if on a different branch?
  • Change div Background jquery
  • How does Linux kernel interrupt the application?
  • Busy indicator not showing up in wpf window [duplicate]
  • Why do underscore prefixed variables exist?