Search code examples
iosobjective-cmultithreadinggrand-central-dispatchbackground-process

Why would calling something from the foreground crash, when calling it from the background does not?


Ok, relatively new (again) to ObjectiveC, coming from a Swift background. In our codebase, we have this line of code...

return _queryURL && ![[UIApplication sharedApplication] canOpenURL:_queryURL];

and while it works, when debugging, Xcode gives a warning stating canOpenURL must be executed from a foreground thread.

'Simple enough' I think... 'I'll just synchronously call it on the foreground thread!' and I update the code as follows...

__block BOOL result = NO;
  
dispatch_sync(dispatch_get_main_queue(), ^{
  result = _queryURL && ![[UIApplication sharedApplication] canOpenURL:_queryURL];
});

return result;

...but now, when executing the line which calls canOpenURL, I get this...

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

Huh?! Why would pushing it to the main thread cause an EXC_BAD_INSTRUCTION crash? Is that a red herring?

More importantly, how do you address this issue?


Solution

  • I've seen that bad instruction error happen when you sync call something on the main thread while you are already on the main thread.

    I think, based on the error and the warning that you get, that you call this sometimes from the background and sometimes while on main. Thus you need to check using e.g.

    NSThread.isMainThread
    

    or similar before you call and then based on that proceed, maybe

    if ( NSThread.isMainThread )
    {
      // my call
    }
    else
    {
      dispatch_sync( dispatch_get_main_queue (), ^ {
        // my call
      } );
    }
    

    However, if it is indeed the case that you sometimes call from main and sometimes from the background, you also need to verify that the logic behind it makes sense.