diff --git a/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h b/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h index ad02e6baf51..523dbe62355 100644 --- a/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h +++ b/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h @@ -108,7 +108,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, readonly, strong, nullable) NSDate *archiveDate; @property(nonatomic, readonly) NSUInteger numberOfBatches; -- (instancetype)init NS_DESIGNATED_INITIALIZER; +- (instancetype)init; - (void)addOperationForTopic:(NSString *)topic withAction:(FIRMessagingTopicAction)action completion:(nullable FIRMessagingTopicOperationCompletion)completion; diff --git a/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.m b/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.m index 3a1afcbbb97..cb2ab50df63 100644 --- a/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.m +++ b/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.m @@ -87,15 +87,22 @@ @interface FIRMessagingPendingTopicsList () @property(nonatomic, strong) FIRMessagingTopicBatch *currentBatch; @property(nonatomic, strong) NSMutableSet *topicsInFlight; +@property(nonatomic, readonly) dispatch_queue_t commandQueue; @end @implementation FIRMessagingPendingTopicsList - (instancetype)init { + return + [self initWithCommandQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)]; +} + +- (instancetype)initWithCommandQueue:(dispatch_queue_t)queue { if (self = [super init]) { _topicBatches = [NSMutableArray array]; _topicsInFlight = [NSMutableSet set]; + _commandQueue = queue; } return self; } @@ -179,7 +186,7 @@ - (void)addOperationForTopic:(NSString *)topic if (self.currentBatch == lastBatch && !topicExistedBefore) { // Add this topic to our ongoing operations FIRMessaging_WEAKIFY(self); - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + dispatch_async(self.commandQueue, ^{ FIRMessaging_STRONGIFY(self); [self resumeOperationsIfNeeded]; }); @@ -223,49 +230,45 @@ - (void)beginUpdateForCurrentBatchTopic:(NSString *)topic { [self.topicsInFlight addObject:topic]; } FIRMessaging_WEAKIFY(self); - [self.delegate - pendingTopicsList:self - requestedUpdateForTopic:topic - action:self.currentBatch.action - completion:^(NSError *error) { - dispatch_async( - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - FIRMessaging_STRONGIFY(self); - @synchronized(self) { - [self.topicsInFlight removeObject:topic]; - - BOOL recoverableError = [self subscriptionErrorIsRecoverable:error]; - if (!error || !recoverableError) { - // Notify our handlers and remove the topic from our batch - NSMutableArray *handlers = self.currentBatch.topicHandlers[topic]; - if (handlers.count) { - dispatch_async(dispatch_get_main_queue(), ^{ - for (FIRMessagingTopicOperationCompletion handler in handlers) { - handler(error); - } - [handlers removeAllObjects]; - }); - } - [self.currentBatch.topics removeObject:topic]; - [self.currentBatch.topicHandlers removeObjectForKey:topic]; - if (self.currentBatch.topics.count == 0) { - // All topic updates successfully finished in this batch, move on - // to the next batch - [self.topicBatches removeObject:self.currentBatch]; - self.currentBatch = nil; - } - [self.delegate pendingTopicsListDidUpdate:self]; - FIRMessaging_WEAKIFY(self); - dispatch_async( - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), - ^{ - FIRMessaging_STRONGIFY(self); - [self resumeOperationsIfNeeded]; - }); - } - } - }); - }]; + [self.delegate pendingTopicsList:self + requestedUpdateForTopic:topic + action:self.currentBatch.action + completion:^(NSError *error) { + dispatch_async(self.commandQueue, ^{ + FIRMessaging_STRONGIFY(self); + @synchronized(self) { + [self.topicsInFlight removeObject:topic]; + + BOOL recoverableError = [self subscriptionErrorIsRecoverable:error]; + if (!error || !recoverableError) { + // Notify our handlers and remove the topic from our batch + NSMutableArray *handlers = self.currentBatch.topicHandlers[topic]; + if (handlers.count) { + dispatch_async(dispatch_get_main_queue(), ^{ + for (FIRMessagingTopicOperationCompletion handler in handlers) { + handler(error); + } + [handlers removeAllObjects]; + }); + } + [self.currentBatch.topics removeObject:topic]; + [self.currentBatch.topicHandlers removeObjectForKey:topic]; + if (self.currentBatch.topics.count == 0) { + // All topic updates successfully finished in this batch, move on + // to the next batch + [self.topicBatches removeObject:self.currentBatch]; + self.currentBatch = nil; + } + [self.delegate pendingTopicsListDidUpdate:self]; + FIRMessaging_WEAKIFY(self); + dispatch_async(self.commandQueue, ^{ + FIRMessaging_STRONGIFY(self); + [self resumeOperationsIfNeeded]; + }); + } + } + }); + }]; } @end diff --git a/FirebaseMessaging/Tests/UnitTests/FIRMessagingPendingTopicsListTest.m b/FirebaseMessaging/Tests/UnitTests/FIRMessagingPendingTopicsListTest.m index b66af811128..b01da26afcd 100644 --- a/FirebaseMessaging/Tests/UnitTests/FIRMessagingPendingTopicsListTest.m +++ b/FirebaseMessaging/Tests/UnitTests/FIRMessagingPendingTopicsListTest.m @@ -23,6 +23,10 @@ #import "FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h" #import "FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h" +@interface FIRMessagingPendingTopicsList (Testing) +- (instancetype)initWithCommandQueue:(dispatch_queue_t)queue; +@end + @interface FIRMessagingPendingTopicsListTest : XCTestCase /// Using this delegate lets us prevent any topic operations from start, making it easy to measure @@ -107,7 +111,8 @@ - (void)testAddTopicsWithDifferentActions { } - (void)testBatchSizeReductionAfterSuccessfulTopicUpdate { - FIRMessagingPendingTopicsList *pendingTopics = [[FIRMessagingPendingTopicsList alloc] init]; + FIRMessagingPendingTopicsList *pendingTopics = [[FIRMessagingPendingTopicsList alloc] + initWithCommandQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)]; pendingTopics.delegate = self.alwaysReadyDelegate; XCTestExpectation *allOperationsCompleted = @@ -145,7 +150,8 @@ - (void)testBatchSizeReductionAfterSuccessfulTopicUpdate { } - (void)testCompletionOfTopicUpdatesInSameThread { - FIRMessagingPendingTopicsList *pendingTopics = [[FIRMessagingPendingTopicsList alloc] init]; + FIRMessagingPendingTopicsList *pendingTopics = [[FIRMessagingPendingTopicsList alloc] + initWithCommandQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)]; pendingTopics.delegate = self.alwaysReadyDelegate; XCTestExpectation *allOperationsSucceededed = @@ -181,7 +187,8 @@ - (void)testCompletionOfTopicUpdatesInSameThread { } - (void)testAddingTopicToCurrentBatchWhileCurrentBatchTopicsInFlight { - FIRMessagingPendingTopicsList *pendingTopics = [[FIRMessagingPendingTopicsList alloc] init]; + FIRMessagingPendingTopicsList *pendingTopics = [[FIRMessagingPendingTopicsList alloc] + initWithCommandQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)]; pendingTopics.delegate = self.alwaysReadyDelegate; NSString *initialTopic = @"/topics/0";