Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>The answer to problem #1</strong></p> <p>I have an NSOperation which calls an Asynchronous operation in its main method which calls back outside the operation and I need to tell the operation its complete and end the NSOperation:</p> <p>The following code is amended from above</p> <pre><code>//you create an NSOperation subclass it includes a main method that //keeps the runloop going as follows //your NSOperation subclass has a BOOL field called "complete" //ADDED: your NSOperation subclass has a BOOL field called "stopRunLoop" //ADDED: your NSOperation subclass has a NSThread * field called "myThread" -(void) main { myThread = [NSThread currentThread]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; //I do some stuff which has async callbacks to the appDelegate or any other class (very common) while (!stopRunLoop &amp;&amp; [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); //in an NSOperation another thread cannot set complete //even with a method call to the operation //this is needed or the thread that actually invoked main and //KVO observation will not see the value change //Also you may need to do post processing before setting complete. //if you just set complete on the thread anything after the //runloop will not be executed. //make sure you are actually done. complete = YES; } -(void) internalComplete { stopRunloop = YES; } //This is needed to stop the runLoop, //just setting the value from another thread will not work, //since the thread that created the NSOperation subclass //copied the member fields to the //stack of the thread that ran the main() method. -(void) setComplete { [self performSelector:@selector(internalComplete) onThread:myThread withObject:nil waitUntilDone:NO]; } //override isFinished same as before -(BOOL) isFinished { return complete; } </code></pre> <p><strong>Answer to problem #2</strong> - You cant use </p> <pre><code>[NSOperationQueue addOperations:.. waitUntilFinished:YES] </code></pre> <p>Because your main thread will not update, but you also have several OTHER operations which must not execute until this NSOperation is complete, and NONE of them should block the main thread.</p> <p>Enter...</p> <pre><code>dispatch_semaphore_t </code></pre> <p>If you have several dependent NSOperations which you need to launch from the main thread, you can pass a dispatch semaphore to the NSOperation, <em>remember that these are Asynchronous calls inside the NSOperation main method</em>, so the NSOperation subclass needs to wait for those callbacks to complete. Also method chaining from callbacks can be a problem.</p> <p>By passing in a semaphore from the main thread you can use [NSOperation addOperations:... waitUntilFinished: NO] and still prevent other operations from executing until your callbacks have all completed.</p> <p>Code for the main thread creating the NSOperation</p> <pre><code>//only one operation will run at a time dispatch_semaphore_t mySemaphore = dispatch_semaphore_create(1); //pass your semaphore into the NSOperation on creation myOperation = [[YourCustomNSOperation alloc] initWithSemaphore:mySemaphore] autorelease]; //call the operation [myOperationQueue addOperations:@[myOperation] waitUntilFinished:NO]; </code></pre> <p>...Code for the NSOperation</p> <pre><code>//In the main method of your Custom NSOperation - (As shown above) add this call before //your method does anything //my custom NSOperation subclass has a field of type dispatch_semaphore_t //named "mySemaphore" -(void) main { myThread = [NSThread currentThread]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; //grab the semaphore or wait until its available dispatch_semaphore_wait(mySemaphore, DISPATCH_TIME_FOREVER); //I do some stuff which has async callbacks to the appDelegate or any other class (very common) while (!stopRunLoop &amp;&amp; [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); //release the semaphore dispatch_semaphore_signal(mySemaphore); complete = YES; } </code></pre> <p>When your callback method on another thread calls setComplete on the NSOperation 3 things will happen, </p> <ol> <li><p>The runloop will be stopped allowing the NSOperation to complete (which it otherwise would not)</p></li> <li><p>The semaphore will be released allowing other operations sharing the semaphore to run</p></li> <li><p>The NSOperation will complete and be dealloced</p></li> </ol> <p>If you use method 2 you can wait on arbitrary asynchronous methods invoked from an NSOperationQueue, know that they will complete the runloop, and you can chain callbacks in any way you like, while never blocking the main thread.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload