RCTUIManagerUtils.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import <Foundation/Foundation.h>
  8. #import <React/RCTAssert.h>
  9. #import <React/RCTDefines.h>
  10. /**
  11. * Queues Problem Intro:
  12. * UIManager queue is a special queue because it has a special relationship with
  13. * the Main queue.
  14. *
  15. * This particular relationship comes from two key factors:
  16. * 1. UIManager initiates execution of many blocks on the Main queue;
  17. * 2. In some cases, we want to initiate (and wait for) some UIManager's work *synchronously* from
  18. * the Main queue.
  19. *
  20. * So, how can we meet these criteria?
  21. * "Pseudo UIManager queue" comes to rescue!
  22. *
  23. * "Pseudo UIManager queue" means the safe execution of typical UIManager's work
  24. * on the Main queue while the UIManager queue is explicitly blocked for preventing
  25. * simultaneous/concurrent memory access.
  26. *
  27. * So, how can we technically do this?
  28. * 1. `RCTAssertUIManagerQueue` is okay with execution on both actual UIManager and
  29. * Pseudo UIManager queues.
  30. * 2. Both `RCTExecuteOnUIManagerQueue` and `RCTUnsafeExecuteOnUIManagerQueueSync`
  31. * execute given block *synchronously* if they were called on actual UIManager
  32. * or Pseudo UIManager queues.
  33. * 3. `RCTExecuteOnMainQueue` executes given block *synchronously* if we already on
  34. * the Main queue.
  35. * 4. `RCTUnsafeExecuteOnUIManagerQueueSync` is smart enough to do the trick:
  36. * It detects calling on the Main queue and in this case, instead of doing
  37. * trivial *synchronous* dispatch, it does:
  38. * - Block the Main queue;
  39. * - Dispatch the special block on UIManager queue to block the queue and
  40. * concurrent memory access;
  41. * - Execute the given block on the Main queue;
  42. * - Unblock the UIManager queue.
  43. *
  44. * Imagine the analogy: We have two queues: the Main one and UIManager one.
  45. * And these queues are two lanes of railway that go in parallel. Then,
  46. * at some point, we merge UIManager lane with the Main lane, and all cars use
  47. * the unified the Main lane.
  48. * And then we split lanes again.
  49. *
  50. * This solution assumes that the code running on UIManager queue will never
  51. * *explicitly* block the Main queue via calling `RCTUnsafeExecuteOnMainQueueSync`.
  52. * Otherwise, it can cause a deadlock.
  53. */
  54. /**
  55. * Returns UIManager queue.
  56. */
  57. RCT_EXTERN dispatch_queue_t RCTGetUIManagerQueue(void);
  58. /**
  59. * Default name for the UIManager queue.
  60. */
  61. RCT_EXTERN char *const RCTUIManagerQueueName;
  62. /**
  63. * Check if we are currently on UIManager queue.
  64. * Please do not use this unless you really know what you're doing.
  65. */
  66. RCT_EXTERN BOOL RCTIsUIManagerQueue(void);
  67. /**
  68. * Check if we are currently on Pseudo UIManager queue.
  69. * Please do not use this unless you really know what you're doing.
  70. */
  71. RCT_EXTERN BOOL RCTIsPseudoUIManagerQueue(void);
  72. /**
  73. * *Asynchronously* executes the specified block on the UIManager queue.
  74. * Unlike `dispatch_async()` this will execute the block immediately
  75. * if we're already on the UIManager queue.
  76. */
  77. RCT_EXTERN void RCTExecuteOnUIManagerQueue(dispatch_block_t block);
  78. /**
  79. * *Synchronously* executes the specified block on the UIManager queue.
  80. * Unlike `dispatch_sync()` this will execute the block immediately
  81. * if we're already on the UIManager queue.
  82. * Please do not use this unless you really know what you're doing.
  83. */
  84. RCT_EXTERN void RCTUnsafeExecuteOnUIManagerQueueSync(dispatch_block_t block);
  85. /**
  86. * Convenience macro for asserting that we're running on UIManager queue.
  87. */
  88. #define RCTAssertUIManagerQueue() \
  89. RCTAssert( \
  90. RCTIsUIManagerQueue() || RCTIsPseudoUIManagerQueue(), @"This function must be called on the UIManager queue")
  91. /**
  92. * Returns new unique root view tag.
  93. */
  94. RCT_EXTERN NSNumber *RCTAllocateRootViewTag(void);