RCTUIManagerUtils.m 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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 "RCTUIManagerUtils.h"
  8. #import <libkern/OSAtomic.h>
  9. #import "RCTAssert.h"
  10. char *const RCTUIManagerQueueName = "com.facebook.react.ShadowQueue";
  11. static BOOL pseudoUIManagerQueueFlag = NO;
  12. dispatch_queue_t RCTGetUIManagerQueue(void)
  13. {
  14. static dispatch_queue_t shadowQueue;
  15. static dispatch_once_t onceToken;
  16. dispatch_once(&onceToken, ^{
  17. if ([NSOperation instancesRespondToSelector:@selector(qualityOfService)]) {
  18. dispatch_queue_attr_t attr =
  19. dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0);
  20. shadowQueue = dispatch_queue_create(RCTUIManagerQueueName, attr);
  21. } else {
  22. shadowQueue = dispatch_queue_create(RCTUIManagerQueueName, DISPATCH_QUEUE_SERIAL);
  23. dispatch_set_target_queue(shadowQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
  24. }
  25. });
  26. return shadowQueue;
  27. }
  28. BOOL RCTIsUIManagerQueue()
  29. {
  30. static void *queueKey = &queueKey;
  31. static dispatch_once_t onceToken;
  32. dispatch_once(&onceToken, ^{
  33. dispatch_queue_set_specific(RCTGetUIManagerQueue(), queueKey, queueKey, NULL);
  34. });
  35. return dispatch_get_specific(queueKey) == queueKey;
  36. }
  37. BOOL RCTIsPseudoUIManagerQueue()
  38. {
  39. if (RCTIsMainQueue()) {
  40. return pseudoUIManagerQueueFlag;
  41. }
  42. return NO;
  43. }
  44. void RCTExecuteOnUIManagerQueue(dispatch_block_t block)
  45. {
  46. if (RCTIsUIManagerQueue() || RCTIsPseudoUIManagerQueue()) {
  47. block();
  48. } else {
  49. dispatch_async(RCTGetUIManagerQueue(), ^{
  50. block();
  51. });
  52. }
  53. }
  54. void RCTUnsafeExecuteOnUIManagerQueueSync(dispatch_block_t block)
  55. {
  56. if (RCTIsUIManagerQueue() || RCTIsPseudoUIManagerQueue()) {
  57. block();
  58. } else {
  59. if (RCTIsMainQueue()) {
  60. dispatch_semaphore_t mainQueueBlockingSemaphore = dispatch_semaphore_create(0);
  61. dispatch_semaphore_t uiManagerQueueBlockingSemaphore = dispatch_semaphore_create(0);
  62. // Dispatching block which blocks UI Manager queue.
  63. dispatch_async(RCTGetUIManagerQueue(), ^{
  64. // Initiating `block` execution on main queue.
  65. dispatch_semaphore_signal(mainQueueBlockingSemaphore);
  66. // Waiting for finishing `block`.
  67. dispatch_semaphore_wait(uiManagerQueueBlockingSemaphore, DISPATCH_TIME_FOREVER);
  68. });
  69. // Waiting for block on UIManager queue.
  70. dispatch_semaphore_wait(mainQueueBlockingSemaphore, DISPATCH_TIME_FOREVER);
  71. pseudoUIManagerQueueFlag = YES;
  72. // `block` execution while UIManager queue is blocked by semaphore.
  73. block();
  74. pseudoUIManagerQueueFlag = NO;
  75. // Signalling UIManager block.
  76. dispatch_semaphore_signal(uiManagerQueueBlockingSemaphore);
  77. } else {
  78. dispatch_sync(RCTGetUIManagerQueue(), ^{
  79. block();
  80. });
  81. }
  82. }
  83. }
  84. NSNumber *RCTAllocateRootViewTag()
  85. {
  86. // Numbering of these tags goes from 1, 11, 21, 31, ..., 100501, ...
  87. static int64_t rootViewTagCounter = -1;
  88. return @(OSAtomicIncrement64(&rootViewTagCounter) * 10 + 1);
  89. }