Search code examples
objective-casynchronousbackground-processdispatch-async

iOS app behaves differently with debug vs release scheme


In my app I have three internet operations that run at once. They don't depend on each other so I run each of them in a background thread. They each need to be complete though before my app can move on to the completion handler.

The method that starts each of the three receives as a parameter, block code that functions as a completion handler. This method also has a local variable called internetOperationsRemaining that I set equal to 3 before I start each of the three internet operations.

When each of the internet operations is complete I decrement internetOperationsRemaining on the main thread. This results in internetOperationsRemaining == 0 when they are all complete.

To listen for this condition I run a tight loop on another background thread that simply loops on itself waiting for internetOperationsRemaining to equal 0. Once that happens I call the completion handler that was passed in as a parameter as previously described.

    //Spawn a background thread and loop in it until
    //allInternetOperationComplete == true.

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        while(internetOperationsRemaining > 0)
        {
            //Just spins in here on a background thread waiting 
            //on the internet to finish.
        }

        //Now that internetOperationsRemaining == 0, kill the NSURL session 
        //and call the completion handler on the main thread.

        dispatch_async(dispatch_get_main_queue(), ^{
            [session finishTasksAndInvalidate];
            completionHandler();   
        });
  });

The strange behavior that I am seeing is that the app runs perfectly if I have debug set in the scheme, and it doesn't if I have release selected. It simply never breaks out of the while loop.

If I insert some trivial code in the while loop to slow things down just a little it works fine in both debug and release.

    while(internetOperationsRemaining > 0)
    {
        //Just spins in here on a background thread waiting 
        //on the internet to finish.
        int i=0;
        ++i;
    }

I am at a loss to explain this behavior. The tight loop is on a background thread so the app remains responsive to user input as would be expected. I realize that the release scheme introduces optimizations, but I am surprised it actually changed the apps behavior.


Solution

  • Without running code to check, I would think that what is going on is some sort of compiler optimisation which only occurs in Release code.

    I think the real problem though is more about design. Using counters and having a thread spinning is not great. I would suggest looking into using NSOperations. You can setup hierarchies of operations so that your completion operation is dependant on the other three. Go read up on using operations, concurrent queues and dependencies and you will get the idea.