diff options
Diffstat (limited to 'Firestore/Source/API/FIRFirestore.m')
-rw-r--r-- | Firestore/Source/API/FIRFirestore.m | 115 |
1 files changed, 74 insertions, 41 deletions
diff --git a/Firestore/Source/API/FIRFirestore.m b/Firestore/Source/API/FIRFirestore.m index 7814ce1..9df3711 100644 --- a/Firestore/Source/API/FIRFirestore.m +++ b/Firestore/Source/API/FIRFirestore.m @@ -50,13 +50,17 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; @property(nonatomic, strong) id<FSTCredentialsProvider> credentialsProvider; @property(nonatomic, strong) FSTDispatchQueue *workerDispatchQueue; -@property(nonatomic, strong) FSTFirestoreClient *client; +// Note that `client` is updated after initialization, but marking this readwrite would generate an +// incorrect setter (since we make the assignment to `client` inside an `@synchronized` block. +@property(nonatomic, strong, readonly) FSTFirestoreClient *client; @property(nonatomic, strong, readonly) FSTUserDataConverter *dataConverter; @end @implementation FIRFirestore { + // All guarded by @synchronized(self) FIRFirestoreSettings *_settings; + FSTFirestoreClient *_client; } + (NSMutableDictionary<NSString *, FIRFirestore *> *)instances { @@ -154,64 +158,74 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; } - (FIRFirestoreSettings *)settings { - // Disallow mutation of our internal settings - return [_settings copy]; + @synchronized(self) { + // Disallow mutation of our internal settings + return [_settings copy]; + } } - (void)setSettings:(FIRFirestoreSettings *)settings { - // As a special exception, don't throw if the same settings are passed repeatedly. This should - // make it more friendly to create a Firestore instance. - if (_client && ![_settings isEqual:settings]) { - FSTThrowInvalidUsage(@"FIRIllegalStateException", - @"Firestore instance has already been started and its settings can no " - "longer be changed. You can only set settings before calling any " - "other methods on a Firestore instance."); + @synchronized(self) { + // As a special exception, don't throw if the same settings are passed repeatedly. This should + // make it more friendly to create a Firestore instance. + if (_client && ![_settings isEqual:settings]) { + FSTThrowInvalidUsage(@"FIRIllegalStateException", + @"Firestore instance has already been started and its settings can no " + "longer be changed. You can only set settings before calling any " + "other methods on a Firestore instance."); + } + _settings = [settings copy]; } - _settings = [settings copy]; } /** - * Ensures that the FirestoreClient is configured. - * @return self + * Ensures that the FirestoreClient is configured and returns it. */ -- (instancetype)firestoreWithConfiguredClient { - if (!_client) { - // These values are validated elsewhere; this is just double-checking: - FSTAssert(_settings.host, @"FirestoreSettings.host cannot be nil."); - FSTAssert(_settings.dispatchQueue, @"FirestoreSettings.dispatchQueue cannot be nil."); - - FSTDatabaseInfo *databaseInfo = - [FSTDatabaseInfo databaseInfoWithDatabaseID:_databaseID - persistenceKey:_persistenceKey - host:_settings.host - sslEnabled:_settings.sslEnabled]; - - FSTDispatchQueue *userDispatchQueue = [FSTDispatchQueue queueWith:_settings.dispatchQueue]; - - _client = [FSTFirestoreClient clientWithDatabaseInfo:databaseInfo - usePersistence:_settings.persistenceEnabled - credentialsProvider:_credentialsProvider - userDispatchQueue:userDispatchQueue - workerDispatchQueue:_workerDispatchQueue]; +- (FSTFirestoreClient *)client { + [self ensureClientConfigured]; + return _client; +} + +- (void)ensureClientConfigured { + @synchronized(self) { + if (!_client) { + // These values are validated elsewhere; this is just double-checking: + FSTAssert(_settings.host, @"FirestoreSettings.host cannot be nil."); + FSTAssert(_settings.dispatchQueue, @"FirestoreSettings.dispatchQueue cannot be nil."); + + FSTDatabaseInfo *databaseInfo = + [FSTDatabaseInfo databaseInfoWithDatabaseID:_databaseID + persistenceKey:_persistenceKey + host:_settings.host + sslEnabled:_settings.sslEnabled]; + + FSTDispatchQueue *userDispatchQueue = [FSTDispatchQueue queueWith:_settings.dispatchQueue]; + + _client = [FSTFirestoreClient clientWithDatabaseInfo:databaseInfo + usePersistence:_settings.persistenceEnabled + credentialsProvider:_credentialsProvider + userDispatchQueue:userDispatchQueue + workerDispatchQueue:_workerDispatchQueue]; + } } - return self; } - (FIRCollectionReference *)collectionWithPath:(NSString *)collectionPath { if (!collectionPath) { FSTThrowInvalidArgument(@"Collection path cannot be nil."); } + [self ensureClientConfigured]; FSTResourcePath *path = [FSTResourcePath pathWithString:collectionPath]; - return - [FIRCollectionReference referenceWithPath:path firestore:self.firestoreWithConfiguredClient]; + return [FIRCollectionReference referenceWithPath:path firestore:self]; } - (FIRDocumentReference *)documentWithPath:(NSString *)documentPath { if (!documentPath) { FSTThrowInvalidArgument(@"Document path cannot be nil."); } + [self ensureClientConfigured]; FSTResourcePath *path = [FSTResourcePath pathWithString:documentPath]; - return [FIRDocumentReference referenceWithPath:path firestore:self.firestoreWithConfiguredClient]; + return [FIRDocumentReference referenceWithPath:path firestore:self]; } - (void)runTransactionWithBlock:(id _Nullable (^)(FIRTransaction *, NSError **))updateBlock @@ -241,12 +255,13 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; internalCompletion(result, error); }); }; - [self firestoreWithConfiguredClient]; [self.client transactionWithRetries:5 updateBlock:wrappedUpdate completion:completion]; } - (FIRWriteBatch *)batch { - return [FIRWriteBatch writeBatchWithFirestore:[self firestoreWithConfiguredClient]]; + [self ensureClientConfigured]; + + return [FIRWriteBatch writeBatchWithFirestore:self]; } - (void)runTransactionWithBlock:(id _Nullable (^)(FIRTransaction *, NSError **error))updateBlock @@ -264,11 +279,19 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; } - (void)shutdownWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { - if (!self.client) { + FSTFirestoreClient *client; + @synchronized(self) { + client = _client; + _client = nil; + } + + if (!client) { + // We should be dispatching the callback on the user dispatch queue but if the client is nil + // here that queue was never created. completion(nil); - return; + } else { + [client shutdownWithCompletion:completion]; } - return [self.client shutdownWithCompletion:completion]; } + (BOOL)isLoggingEnabled { @@ -279,6 +302,16 @@ NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; FIRSetLoggerLevel(logging ? FIRLoggerLevelDebug : FIRLoggerLevelNotice); } +- (void)enableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable error))completion { + [self ensureClientConfigured]; + [self.client enableNetworkWithCompletion:completion]; +} + +- (void)disableNetworkWithCompletion:(nullable void (^)(NSError *_Nullable))completion { + [self ensureClientConfigured]; + [self.client disableNetworkWithCompletion:completion]; +} + @end NS_ASSUME_NONNULL_END |