Make selections in a subclass of NSOperation

I could not find the answer anywhere on the net, so any help would be appreciated.

I will contact to create a system in which I can get the results of the NSOperation task, which, as I understand it, cannot be performed using specific subclasses such as NSInvocation.

I have a subclass of NSOperation ( TheEngine ), which is abstract by convention and needs to be extended to implement the -main function to include the body of the executable code.

TheEngine contains the following initialization function, the task of which is simply to mark theSelector and theObject to which the selector belongs. It also registers the KV observer for the isFinished property:

 -(id)initWithCallbackSelector:(SEL)theSelector inObject:(id)theObject 

In my function observeValueForKeyPath:ofObject:change:context: I would like to call the callback function as follows:

 NSLog(@"Some debug text to ensure this function is being called", nil); [theObject performSelector:theSelector withObject:someData afterDelay:0]; 

The whole process is as follows:

aViewController launches TheEngine extension - allows you to tell TheTask by invoking the following and adding it to the operation queue.

 TheTask* TT = [[TheTask alloc] initWithCallbackSelector: @selector(resultHandler:) inObject:theObject]; 

Everything seems to work as expected without any errors or exceptions. But when the execution reaches observeValueForKeyPath:ofObject:change:context: callback is not actually called. I am new to Obj-C, so I'm not quite sure if I understand this type of thread correctly.

Here is the whole 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!

+2
source share
2 answers

Your NSOperation most likely runs in the background thread. If this thread disappears, or if this thread fails to pump its start loop, then your call to performSelector:withObject:afterDelay: will not fire. You commented on the call to performSelectorOnMainThread:... Did it work?

You should probably run this in the main thread or run it using performSelector:withObject: (without afterDelay: . performSelector:withObject: does not require a run loop.

+1
source

As Rob suggested, the code worked in the background thread, like the call to observeValueForKeyPath:ofObject:change:context:

I initially changed the code so that the selector is started in the main thread using [self performSelectorOnMainThread:@selector(runCallback) withObject:nil waitUntilDone:NO]; .

But in this case, the main thread is TheTask , and the exception was thrown as TheTask does not belong to theSelector . To fix this, I created an additional function -runCallback and released 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 -runCallback :

 -(void)runCallback{ [self.selectorsParentObject performSelector:self.selectorToCallWhenFinished withObject:self.resultData afterDelay:0]; } 

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

0
source

Source: https://habr.com/ru/post/1388616/


All Articles