From cca3c13d2dffd8c4c7eed270bbabffa0fa23be14 Mon Sep 17 00:00:00 2001 From: Evan Bacon Date: Fri, 8 Jun 2018 14:44:48 -0700 Subject: [PATCH] Fixed Deadlock Running this in a detached expo app can sometimes deadlock from thread issues. I've replaced `dispatch_sync(dispatch_get_main_queue(), ^{});` with `RCTUnsafeExecuteOnMainQueueSync(^{});` to fix this. I only hit the error in the `RNFirebaseStorage.m` but it seems like the `RNFirebaseAnalytics.m` and `RNFirebase.m` modules could also have this same issue. `RCTUnsafeExecuteOnMainQueueSync` checks to see if the method is being executed on the main thread before trying to sync to the main thread. If you try to sync on the main thread whilst on the main thread, you hit a deadlock. You can read more about it here: https://stackoverflow.com/questions/12379059/why-is-this-dispatch-sync-call-freezing?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa The only testing I did was in a seperate detached ExpoKit project. Running this function would cause the crash. ```js await firebase .storage() .ref(uploadUri) .putFile(uri); ``` --- ios/RNFirebase/RNFirebase.m | 3 ++- ios/RNFirebase/analytics/RNFirebaseAnalytics.m | 3 ++- ios/RNFirebase/storage/RNFirebaseStorage.m | 7 ++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ios/RNFirebase/RNFirebase.m b/ios/RNFirebase/RNFirebase.m index 6f05d927..981d3893 100644 --- a/ios/RNFirebase/RNFirebase.m +++ b/ios/RNFirebase/RNFirebase.m @@ -1,6 +1,7 @@ #import "RNFirebase.h" #import "RNFirebaseUtil.h" #import +#import @implementation RNFirebase RCT_EXPORT_MODULE(RNFirebase); @@ -28,7 +29,7 @@ RCT_EXPORT_METHOD(initializeApp: callback: (RCTResponseSenderBlock) callback) { - dispatch_sync(dispatch_get_main_queue(), ^{ + RCTUnsafeExecuteOnMainQueueSync(^{ FIRApp *existingApp = [RNFirebaseUtil getApp:appDisplayName]; if (!existingApp) { diff --git a/ios/RNFirebase/analytics/RNFirebaseAnalytics.m b/ios/RNFirebase/analytics/RNFirebaseAnalytics.m index f896b06d..91de5476 100644 --- a/ios/RNFirebase/analytics/RNFirebaseAnalytics.m +++ b/ios/RNFirebase/analytics/RNFirebaseAnalytics.m @@ -1,4 +1,5 @@ #import "RNFirebaseAnalytics.h" +#import #if __has_include() #import @@ -16,7 +17,7 @@ RCT_EXPORT_METHOD(setAnalyticsCollectionEnabled:(BOOL) enabled) { } RCT_EXPORT_METHOD(setCurrentScreen:(NSString *) screenName screenClass:(NSString *) screenClassOverriew) { - dispatch_sync(dispatch_get_main_queue(), ^{ + RCTUnsafeExecuteOnMainQueueSync(^{ [FIRAnalytics setScreenName:screenName screenClass:screenClassOverriew]; }); } diff --git a/ios/RNFirebase/storage/RNFirebaseStorage.m b/ios/RNFirebase/storage/RNFirebaseStorage.m index 8048f7f9..8b470d44 100644 --- a/ios/RNFirebase/storage/RNFirebaseStorage.m +++ b/ios/RNFirebase/storage/RNFirebaseStorage.m @@ -7,6 +7,7 @@ #import #import #import +#import @implementation RNFirebaseStorage @@ -120,7 +121,7 @@ RCT_EXPORT_METHOD(downloadFile:(NSString *) appDisplayName NSURL *localFile = [NSURL fileURLWithPath:localPath]; __block FIRStorageDownloadTask *downloadTask; - dispatch_sync(dispatch_get_main_queue(), ^{ + RCTUnsafeExecuteOnMainQueueSync(^{ downloadTask = [fileRef writeToFile:localFile]; }); @@ -298,7 +299,7 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName - (void)uploadFile:(NSString *)appDisplayName url:(NSURL *)url firmetadata:(FIRStorageMetadata *)firmetadata path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject { FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName]; __block FIRStorageUploadTask *uploadTask; - dispatch_sync(dispatch_get_main_queue(), ^{ + RCTUnsafeExecuteOnMainQueueSync(^{ uploadTask = [fileRef putFile:url metadata:firmetadata]; }); [self addUploadObservers:appDisplayName uploadTask:uploadTask path:path resolver:resolve rejecter:reject]; @@ -307,7 +308,7 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName - (void)uploadData:(NSString *)appDisplayName data:(NSData *)data firmetadata:(FIRStorageMetadata *)firmetadata path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject { FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName]; __block FIRStorageUploadTask *uploadTask; - dispatch_sync(dispatch_get_main_queue(), ^{ + RCTUnsafeExecuteOnMainQueueSync(^{ uploadTask = [fileRef putData:data metadata:firmetadata]; }); [self addUploadObservers:appDisplayName uploadTask:uploadTask path:path resolver:resolve rejecter:reject];