Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSOperation is not happening in background thread

I created an NSOperation subclass to handle some zip archive operations. No matter what, if I override -start or -main this block of code always happens:

if ([NSThread isMainThread]) {
    NSLog(@"I am in the main thread");
    return;
}

Any idea what's going on?

I've tried adding this block:

- (void) start {  //also tried overriding main

    if ([NSThread isMainThread]) {
        NSLog(@"In main thread, trying again");
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self start];
        });
        return;
        //hard working code etc...
        //cpu intensive zip operations...
    }

But this causes a crash, an EXC_BAD_ACCESS violation pointing at the dispatch_async line.

like image 825
Daddy Avatar asked Aug 05 '13 02:08

Daddy


People also ask

When to use GCD vs NSOperation?

Grand Central Dispatch is ideal if you just need to dispatch a block of code to a serial or concurrent queue. If you don't want to go through the hassle of creating an NSOperation subclass for a trivial task, then Grand Central Dispatch is a great alternative.

Which is the best of GCD NSthread or NSOperationQueue?

NSOperationQueue works best when tasks are discrete, synchronous and live in the same thread (eg they are more or less atomic), the queue can be used as basic thread pool though in almost any situation.

Is NSOperationQueue concurrent?

NSOperationQueue always executes operations concurrently, while taking dependencies into account. A "non-concurrent" operation requires a separate thread in order to execute concurrently.

What is NSOperation queue?

A queue that regulates the execution of operations.


1 Answers

No matter what, if I override -start or -main this block of code always happens:

The main operation queue runs on the main thread. From the docs for +[NSOperationQueue mainQueue]:

The returned queue executes operations on the main thread. The main thread’s run loop controls the execution times of these operations.

So, running in another thread is a matter of what queue you add the operation to, not how you write the operation's code. If you want your operation to run on a different operation queue, you'll need to create a queue of your own using

NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];

You can find an example in Adding Operations to an Operation Queue in the Concurrency Programming Guide.

But this causes a crash, an EXC_BAD_ACCESS violation pointing at the dispatch_async line.

It sounds like -[NSOperation start] probably isn't re-entrant. Your code effectively executes the same method on two different threads. In fact, look at the docs for -start, it's obvious that your code won't work:

You can call this method explicitly if you want to execute your operations manually. However, it is a programmer error to call this method on an operation object that is already in an operation queue or to queue the operation after calling this method. Once you add an operation object to a queue, the queue assumes all responsibility for it. [Emphasis added. -Caleb]

In other words, don't do that.

like image 99
Caleb Avatar answered Sep 19 '22 15:09

Caleb