@@ -66,6 +66,8 @@ @implementation FIRCrashlytics
6666static FIRExceptionModel *sLastRecordedExceptionModel ;
6767static NSMutableArray <FIRExceptionModel *> *sSavedExceptionModels ;
6868static void (^sOnExceptionModelSaved )(FIRExceptionModel *);
69+ static BOOL sContextInitPending ;
70+ static NSMutableArray <dispatch_block_t > *sPendingSaves ;
6971// Bumped by resetTestState so saves enqueued by an earlier test are dropped.
7072static atomic_uint_fast64_t sSaveGeneration ;
7173
@@ -74,6 +76,7 @@ + (void)initialize {
7476 sLoggedMessages = [NSMutableArray new ];
7577 sCustomValues = [NSMutableDictionary new ];
7678 sSavedExceptionModels = [NSMutableArray new ];
79+ sPendingSaves = [NSMutableArray new ];
7780 }
7881}
7982
@@ -168,6 +171,24 @@ + (void)setOnExceptionModelSaved:(void (^)(FIRExceptionModel *))onExceptionModel
168171 sOnExceptionModelSaved = [onExceptionModelSaved copy ];
169172}
170173
174+ + (void )holdContextInit {
175+ @synchronized (sPendingSaves ) {
176+ sContextInitPending = YES ;
177+ }
178+ }
179+
180+ + (void )fulfillContextInit {
181+ NSArray <dispatch_block_t > *saves;
182+ @synchronized (sPendingSaves ) {
183+ sContextInitPending = NO ;
184+ saves = [sPendingSaves copy ];
185+ [sPendingSaves removeAllObjects ];
186+ }
187+ for (dispatch_block_t save in saves) {
188+ dispatch_async (dispatch_get_main_queue (), save);
189+ }
190+ }
191+
171192+ (void )resetTestState {
172193 sDidCrashDuringPreviousExecutionValue = NO ;
173194 sCheckForUnsentReportsValue = NO ;
@@ -179,6 +200,10 @@ + (void)resetTestState {
179200 sLastRecordedExceptionModel = nil ;
180201 [sSavedExceptionModels removeAllObjects ];
181202 sOnExceptionModelSaved = nil ;
203+ @synchronized (sPendingSaves ) {
204+ sContextInitPending = NO ;
205+ [sPendingSaves removeAllObjects ];
206+ }
182207 atomic_fetch_add (&sSaveGeneration , 1 );
183208}
184209
@@ -224,17 +249,25 @@ - (void)setUserID:(NSString *)userID {
224249- (void )recordExceptionModel : (FIRExceptionModel *)exceptionModel {
225250 sLastRecordedExceptionModel = exceptionModel;
226251 // Mirrors FirebaseCrashlytics: once context init is fulfilled, the save block is dispatched to
227- // the main queue and writes synchronously when it runs.
252+ // the main queue and writes synchronously when it runs. While init is pending, FBLPromise holds
253+ // the block as an observer and dispatches it to the main queue only when the promise fulfills.
228254 uint_fast64_t generation = atomic_load (&sSaveGeneration );
229- dispatch_async ( dispatch_get_main_queue (), ^{
255+ dispatch_block_t save = ^{
230256 if (generation != atomic_load (&sSaveGeneration )) {
231257 return ;
232258 }
233259 [sSavedExceptionModels addObject: exceptionModel];
234260 if (sOnExceptionModelSaved != nil ) {
235261 sOnExceptionModelSaved (exceptionModel);
236262 }
237- });
263+ };
264+ @synchronized (sPendingSaves ) {
265+ if (sContextInitPending ) {
266+ [sPendingSaves addObject: save];
267+ return ;
268+ }
269+ }
270+ dispatch_async (dispatch_get_main_queue (), save);
238271}
239272
240273@end
0 commit comments