@@ -36,6 +36,9 @@ @interface FIRDatabase ()
36
36
37
37
@implementation FIRDatabase
38
38
39
+ /* * A NSMutableDictionary of FirebaseApp name and FRepoInfo to FirebaseDatabase instance. */
40
+ typedef NSMutableDictionary <NSString *, NSMutableDictionary <FRepoInfo *, FIRDatabase *> *> FIRDatabaseDictionary;
41
+
39
42
// The STR and STR_EXPAND macro allow a numeric version passed to he compiler driver
40
43
// with a -D to be treated as a string instead of an invalid floating point value.
41
44
#define STR (x ) STR_EXPAND(x)
@@ -51,30 +54,34 @@ + (void)load {
51
54
NSString *appName = note.userInfo [kFIRAppNameKey ];
52
55
if (appName == nil ) { return ; }
53
56
54
- NSMutableDictionary * instances = [self instances ];
57
+ FIRDatabaseDictionary* instances = [self instances ];
55
58
@synchronized (instances) {
56
- FIRDatabase *deletedApp = instances[appName];
57
- if (deletedApp ) {
59
+ NSMutableDictionary <FRepoInfo *, FIRDatabase *> *databaseInstances = instances[appName];
60
+ if (databaseInstances ) {
58
61
// Clean up the deleted instance in an effort to remove any resources still in use.
59
62
// Note: Any leftover instances of this exact database will be invalid.
60
- [FRepoManager disposeRepos: deletedApp.config];
63
+ for (FIRDatabase * database in [databaseInstances allValues ]) {
64
+ [FRepoManager disposeRepos: database.config];
65
+ }
61
66
[instances removeObjectForKey: appName];
62
67
}
63
68
}
64
69
}];
65
70
}
66
71
67
72
/* *
68
- * A static NSMutableDictionary of FirebaseApp names to FirebaseDatabase instance. To ensure thread-
69
- * safety, it should only be accessed in databaseForApp, which is synchronized.
73
+ * A static NSMutableDictionary of FirebaseApp name and FRepoInfo to
74
+ * FirebaseDatabase instance. To ensure thread-safety, it should only be
75
+ * accessed in databaseForApp:URL:, which is synchronized.
70
76
*
71
77
* TODO: This serves a duplicate purpose as RepoManager. We should clean up.
72
- * TODO: We should maybe be conscious of leaks and make this a weak map or similar
73
- * but we have a lot of work to do to allow FirebaseDatabase/Repo etc. to be GC'd.
78
+ * TODO: We should maybe be conscious of leaks and make this a weak map or
79
+ * similar but we have a lot of work to do to allow FirebaseDatabase/Repo etc.
80
+ * to be GC'd.
74
81
*/
75
- + (NSMutableDictionary *)instances {
82
+ + (FIRDatabaseDictionary *)instances {
76
83
static dispatch_once_t pred = 0 ;
77
- static NSMutableDictionary *instances;
84
+ static FIRDatabaseDictionary *instances;
78
85
dispatch_once (&pred, ^{
79
86
instances = [NSMutableDictionary dictionary ];
80
87
});
@@ -92,27 +99,59 @@ + (FIRDatabase *)database {
92
99
return [FIRDatabase databaseForApp: app];
93
100
}
94
101
102
+ + (FIRDatabase *)databaseWithURL : (NSString *)url {
103
+ FIRApp *app = [FIRApp defaultApp ];
104
+ if (app == nil ) {
105
+ [NSException raise: @" FIRAppNotConfigured"
106
+ format: @" Failed to get default Firebase Database instance. "
107
+ @" Must call `[FIRApp configure]` (`FirebaseApp.configure()` in Swift) "
108
+ @" before using Firebase Database." ];
109
+ }
110
+ return [FIRDatabase databaseForApp: app URL: url];
111
+ }
112
+
95
113
+ (FIRDatabase *)databaseForApp : (FIRApp *)app {
96
114
if (app == nil ) {
97
115
[NSException raise: @" InvalidFIRApp" format: @" nil FIRApp instance passed to databaseForApp." ];
98
116
}
99
- NSMutableDictionary *instances = [self instances ];
100
- @synchronized (instances) {
101
- FIRDatabase *database = instances[app.name];
102
- if (!database) {
103
- NSString *databaseUrl = app.options .databaseURL ;
104
- if (databaseUrl == nil ) {
105
- [NSException raise: @" MissingDatabaseURL" format: @" Failed to get FIRDatabase instance: FIRApp object has no "
106
- " databaseURL in its FirebaseOptions object." ];
107
- }
108
117
109
- FParsedUrl *parsedUrl = [FUtilities parseUrl: databaseUrl];
110
- if (![parsedUrl.path isEmpty ]) {
111
- [NSException raise: @" InvalidDatabaseURL" format: @" Configured Database URL '%@ ' is invalid. It should "
112
- " point to the root of a Firebase Database but it includes a path: %@ " ,
113
- databaseUrl, [parsedUrl.path toString ]];
114
- }
118
+ return [FIRDatabase databaseForApp: app URL: app.options.databaseURL];
119
+ }
115
120
121
+ + (FIRDatabase *)databaseForApp : (FIRApp *)app URL : (NSString *)url {
122
+ if (app == nil ) {
123
+ [NSException raise: @" InvalidFIRApp"
124
+ format: @" nil FIRApp instance passed to databaseForApp." ];
125
+ }
126
+
127
+ if (url == nil ) {
128
+ [NSException raise: @" MissingDatabaseURL"
129
+ format: @" Failed to get FirebaseDatabase instance: "
130
+ " Specify DatabaseURL within FIRApp or from your databaseForApp:URL: call." ];
131
+ }
132
+
133
+ NSURL *databaseUrl = [NSURL URLWithString: url];
134
+
135
+ if (databaseUrl == nil ) {
136
+ [NSException raise: @" InvalidDatabaseURL" format: @" The Database URL '%@ ' cannot be parsed. "
137
+ " Specify a valid DatabaseURL within FIRApp or from your databaseForApp:URL: call." , databaseUrl];
138
+ } else if (![databaseUrl.path isEqualToString: @" " ] && ![databaseUrl.path isEqualToString: @" /" ]) {
139
+ [NSException raise: @" InvalidDatabaseURL" format: @" Configured Database URL '%@ ' is invalid. It should point "
140
+ " to the root of a Firebase Database but it includes a path: %@ " ,databaseUrl, databaseUrl.path];
141
+ }
142
+
143
+ FIRDatabaseDictionary *instances = [self instances ];
144
+ @synchronized (instances) {
145
+ NSMutableDictionary <FRepoInfo *, FIRDatabase *> *urlInstanceMap =
146
+ instances[app.name];
147
+ if (!urlInstanceMap) {
148
+ urlInstanceMap = [NSMutableDictionary dictionary ];
149
+ instances[app.name] = urlInstanceMap;
150
+ }
151
+
152
+ FParsedUrl *parsedUrl = [FUtilities parseUrl: databaseUrl.absoluteString];
153
+ FIRDatabase *database = urlInstanceMap[parsedUrl.repoInfo];
154
+ if (!database) {
116
155
id <FAuthTokenProvider> authTokenProvider = [FAuthTokenProvider authTokenProviderForApp: app];
117
156
118
157
// If this is the default app, don't set the session persistence key so that we use our
@@ -125,8 +164,10 @@ + (FIRDatabase *)databaseForApp:(FIRApp *)app {
125
164
126
165
FIRDatabaseConfig *config = [[FIRDatabaseConfig alloc ] initWithSessionIdentifier: sessionIdentifier
127
166
authTokenProvider: authTokenProvider];
128
- database = [[FIRDatabase alloc ] initWithApp: app repoInfo: parsedUrl.repoInfo config: config];
129
- instances[app.name] = database;
167
+ database = [[FIRDatabase alloc ] initWithApp: app
168
+ repoInfo: parsedUrl.repoInfo
169
+ config: config];
170
+ urlInstanceMap[parsedUrl.repoInfo] = database;
130
171
}
131
172
132
173
return database;
0 commit comments