SRDelegateController.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. //
  2. // Copyright (c) 2016-present, Facebook, Inc.
  3. // All rights reserved.
  4. //
  5. // This source code is licensed under the BSD-style license found in the
  6. // LICENSE file in the root directory of this source tree. An additional grant
  7. // of patent rights can be found in the PATENTS file in the same directory.
  8. //
  9. #import "SRDelegateController.h"
  10. NS_ASSUME_NONNULL_BEGIN
  11. @interface SRDelegateController ()
  12. @property (nonatomic, strong, readonly) dispatch_queue_t accessQueue;
  13. @property (atomic, assign, readwrite) SRDelegateAvailableMethods availableDelegateMethods;
  14. @end
  15. @implementation SRDelegateController
  16. @synthesize delegate = _delegate;
  17. @synthesize dispatchQueue = _dispatchQueue;
  18. @synthesize operationQueue = _operationQueue;
  19. ///--------------------------------------
  20. #pragma mark - Init
  21. ///--------------------------------------
  22. - (instancetype)init
  23. {
  24. self = [super init];
  25. if (!self) return self;
  26. _accessQueue = dispatch_queue_create("com.facebook.socketrocket.delegate.access", DISPATCH_QUEUE_CONCURRENT);
  27. _dispatchQueue = dispatch_get_main_queue();
  28. return self;
  29. }
  30. ///--------------------------------------
  31. #pragma mark - Accessors
  32. ///--------------------------------------
  33. - (void)setDelegate:(id<SRWebSocketDelegate> _Nullable)delegate
  34. {
  35. dispatch_barrier_async(self.accessQueue, ^{
  36. _delegate = delegate;
  37. self.availableDelegateMethods = (SRDelegateAvailableMethods){
  38. .didReceiveMessage = [delegate respondsToSelector:@selector(webSocket:didReceiveMessage:)],
  39. .didReceiveMessageWithString = [delegate respondsToSelector:@selector(webSocket:didReceiveMessageWithString:)],
  40. .didReceiveMessageWithData = [delegate respondsToSelector:@selector(webSocket:didReceiveMessageWithData:)],
  41. .didOpen = [delegate respondsToSelector:@selector(webSocketDidOpen:)],
  42. .didFailWithError = [delegate respondsToSelector:@selector(webSocket:didFailWithError:)],
  43. .didCloseWithCode = [delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)],
  44. .didReceivePing = [delegate respondsToSelector:@selector(webSocket:didReceivePingWithData:)],
  45. .didReceivePong = [delegate respondsToSelector:@selector(webSocket:didReceivePong:)],
  46. .shouldConvertTextFrameToString = [delegate respondsToSelector:@selector(webSocketShouldConvertTextFrameToString:)]
  47. };
  48. });
  49. }
  50. - (id<SRWebSocketDelegate> _Nullable)delegate
  51. {
  52. __block id<SRWebSocketDelegate> delegate = nil;
  53. dispatch_sync(self.accessQueue, ^{
  54. delegate = _delegate;
  55. });
  56. return delegate;
  57. }
  58. - (void)setDispatchQueue:(dispatch_queue_t _Nullable)queue
  59. {
  60. dispatch_barrier_async(self.accessQueue, ^{
  61. _dispatchQueue = queue ?: dispatch_get_main_queue();
  62. _operationQueue = nil;
  63. });
  64. }
  65. - (dispatch_queue_t _Nullable)dispatchQueue
  66. {
  67. __block dispatch_queue_t queue = nil;
  68. dispatch_sync(self.accessQueue, ^{
  69. queue = _dispatchQueue;
  70. });
  71. return queue;
  72. }
  73. - (void)setOperationQueue:(NSOperationQueue *_Nullable)queue
  74. {
  75. dispatch_barrier_async(self.accessQueue, ^{
  76. _dispatchQueue = queue ? nil : dispatch_get_main_queue();
  77. _operationQueue = queue;
  78. });
  79. }
  80. - (NSOperationQueue *_Nullable)operationQueue
  81. {
  82. __block NSOperationQueue *queue = nil;
  83. dispatch_sync(self.accessQueue, ^{
  84. queue = _operationQueue;
  85. });
  86. return queue;
  87. }
  88. ///--------------------------------------
  89. #pragma mark - Perform
  90. ///--------------------------------------
  91. - (void)performDelegateBlock:(SRDelegateBlock)block
  92. {
  93. __block __strong id<SRWebSocketDelegate> delegate = nil;
  94. __block SRDelegateAvailableMethods availableMethods = {};
  95. dispatch_sync(self.accessQueue, ^{
  96. delegate = _delegate; // Not `OK` to go through `self`, since queue sync.
  97. availableMethods = self.availableDelegateMethods; // `OK` to call through `self`, since no queue sync.
  98. });
  99. [self performDelegateQueueBlock:^{
  100. block(delegate, availableMethods);
  101. }];
  102. }
  103. - (void)performDelegateQueueBlock:(dispatch_block_t)block
  104. {
  105. dispatch_queue_t dispatchQueue = self.dispatchQueue;
  106. if (dispatchQueue) {
  107. dispatch_async(dispatchQueue, block);
  108. } else {
  109. [self.operationQueue addOperationWithBlock:block];
  110. }
  111. }
  112. @end
  113. NS_ASSUME_NONNULL_END