Avoid using RCTUnsafeExecuteOnMainQueueSync and similar synchronous main queue dispatch methods as they can cause deadlocks, especially in initialization code, dispatch_once blocks, or when called from background threads that may already hold main queue dependencies.

Deadlocks occur when the main queue is waiting for a background queue, and that background queue then tries to synchronously dispatch back to the main queue. This creates a circular dependency where both queues are blocked waiting for each other.

Instead, use asynchronous alternatives like RCTExecuteOnMainQueue which avoids the jump if already on the main queue, or standard dispatch_async(dispatch_get_main_queue(), ...) when you need to ensure execution at the end of the main queue.

Example of problematic code:

// BAD - Can cause deadlock
- (void)invalidate {
  RCTUnsafeExecuteOnMainQueueSync(^{
    if (_didInvalidate) {
      return;
    }
    // ... invalidation logic
  });
}

Example of safer alternative:

// GOOD - Uses async dispatch to avoid deadlock
- (void)invalidate {
  RCTExecuteOnMainQueue(^{
    if (_didInvalidate) {
      return;
    }
    // ... invalidation logic
  });
}

This pattern is particularly important in React Native’s multi-threaded environment where JavaScript, UI, and background threads frequently interact.