2

As the title says the NSRunLoop's runMode:beforeDate: doesn't wait. What should I do to make the thread to wait with NSRunLoop.

I am running a method on background thread:

[self performSelectorInBackground:@selector(performOperation:) withObject:nil];


- (void)performSynchronousOperation:(operation *)operation
{
    operationComplete = NO;

    // Now wait for response
    NSRunLoop *theRL = [NSRunLoop currentRunLoop];

    while (!operationComplete && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);

    return;
}

Background thread doesn't wait at while loop. Is there anything I am missing?

Rob
  • 415,655
  • 72
  • 787
  • 1,044

2 Answers2

2

A couple of observations:

  1. To keep the run loop alive, you have add a source to it. For example, you can do:

    [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    

    Unfortunately, this will also keep the runMode from completing until the port is removed from the run loop. So, you either have to remove this source when you set operationComplete. Or don't use this runMode method (e.g. perhaps use the CFRunLoopRunInMode Core Foundation function as shown in listing 3-2 in the Threading Programming Guide: Run Loops).

  2. I'm confused by the use of "synchronous" in your method name. If you're doing something synchronous on a background thread, then you don't need to do any of this runloop stuff. This is only needed if doing async tasks on background threads, and even then, there are generally better approaches.

Perhaps you can explain what problem you're trying to solve with your code sample and we can help more.

See Rob Mayoff's answer for other insights.

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Yes, i am trying to perform async network operation in background thread. But the thread waits at the while loop for the below implementation, i dont understand why. `- (void) performSynchronousOperation {` `[operation start];` // network operation will start (operation is a class whose base class is NSOperation and implements its 'main' method) // Now wait for response `NSRunLoop *theRL = [NSRunLoop currentRunLoop];` `while (!operationComplete && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); // thread waits here. dont know why?` `}` – Praveen Kondapalli Feb 03 '16 at 12:57
  • If you're doing an async network operation, you only have to go through this background thread silliness if scheduling `NSURLConnection` on a background thread. But that's deprecated now anyway and you should use `NSURLSession`, in which case you can completely excise this background thread code. And if you're wrapping this in an `NSOperation`, then you should subclass `NSOperation` and make it an asynchronous operation and then enjoy operation dependencies, `maxConcurrentOperationCount`, etc. See the latter part of http://stackoverflow.com/a/21205992/1271826 for an example of how to do that. – Rob Feb 03 '16 at 17:27
  • If you've added the port to the `NSRunLoop`, that will keep the background thread's run loop from exiting, but also prevents `runMode:beforeDate:` from terminating, too. That's why I suggested `CFRunLoopRunInMode` instead. But that point is moot, as you really shouldn't be spinning in a run loop while the network request is in progress, anyway. See my previous comment. – Rob Feb 03 '16 at 17:33
1

Here is what Apple API docs said about this method:

If no input sources or timers are attached to the run loop, this method exits immediately and returns false

That's why it does not wait. Not sure what are you trying to achieve here. However, if you want to do such waiting thing, I recommend using some other ways like dispatch_semaphore.

Eric Qian
  • 2,246
  • 1
  • 18
  • 15