1414
1515import Foundation
1616
17- import FirebaseAppCheck
18- import FirebaseAuth
19- import FirebaseCore
17+ @ preconcurrency import FirebaseAppCheck
18+ @ preconcurrency import FirebaseAuth
19+ @ preconcurrency import FirebaseCore
2020
2121@available ( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
2222public class DataConnect {
@@ -29,7 +29,17 @@ public class DataConnect {
2929
3030 private var callerSDKType : CallerSDKType = . base
3131
32- private static var instanceStore = InstanceStore ( )
32+ private let accessQueue = DispatchQueue (
33+ label: " com.google.firebase.dataConnect.instanceAccessQueue " ,
34+ autoreleaseFrequency: . workItem
35+ )
36+
37+ // Instance store uses an internal queue to protect mutable state.
38+ #if compiler(>=6)
39+ private nonisolated ( unsafe) static let instanceStore = InstanceStore ( )
40+ #else
41+ private static let instanceStore = InstanceStore ( )
42+ #endif
3343
3444 public enum EmulatorDefaults {
3545 public static let host = " 127.0.0.1 "
@@ -62,26 +72,26 @@ public class DataConnect {
6272
6373 public func useEmulator( host: String = EmulatorDefaults . host,
6474 port: Int = EmulatorDefaults . port) {
65- settings = DataConnectSettings ( host: host, port: port, sslEnabled: false )
75+ accessQueue. sync {
76+ settings = DataConnectSettings ( host: host, port: port, sslEnabled: false )
6677
67- // TODO: - shutdown grpc client
68- // self.grpcClient.close
69- // self.operations.close
78+ // TODO: - shutdown grpc client
79+ // self.grpcClient.close
80+ // self.operations.close
7081
71- guard app. options. projectID != nil else {
72- fatalError ( " Firebase DataConnect requires the projectID to be set in the app options " )
73- }
82+ guard app. options. projectID != nil else {
83+ fatalError ( " Firebase DataConnect requires the projectID to be set in the app options " )
84+ }
7485
75- grpcClient = GrpcClient (
76- app: app,
77- settings: settings,
78- connectorConfig: connectorConfig,
79- auth: Auth . auth ( app: app) ,
80- appCheck: AppCheck . appCheck ( app: app) ,
81- callerSDKType: callerSDKType
82- )
86+ grpcClient = GrpcClient (
87+ app: app,
88+ settings: settings,
89+ connectorConfig: connectorConfig,
90+ callerSDKType: callerSDKType
91+ )
8392
84- operationsManager = OperationsManager ( grpcClient: grpcClient)
93+ operationsManager = OperationsManager ( grpcClient: grpcClient)
94+ }
8595 }
8696
8797 // MARK: Init
@@ -101,8 +111,6 @@ public class DataConnect {
101111 app: self . app,
102112 settings: settings,
103113 connectorConfig: connectorConfig,
104- auth: Auth . auth ( app: app) ,
105- appCheck: AppCheck . appCheck ( app: app) ,
106114 callerSDKType: self . callerSDKType
107115 )
108116 operationsManager = OperationsManager ( grpcClient: grpcClient)
@@ -111,33 +119,37 @@ public class DataConnect {
111119 // MARK: Operations
112120
113121 /// Returns a query ref matching the name and variables.
114- public func query< ResultData: Decodable ,
122+ public func query< ResultData: Decodable & Sendable ,
115123 Variable: OperationVariable > ( name: String ,
116124 variables: Variable ,
117125 resultsDataType: ResultData
118126 . Type ,
119127 publisher: ResultsPublisherType = . observableObject)
120128 -> any ObservableQueryRef {
121- let request = QueryRequest ( operationName: name, variables: variables)
122- return operationsManager. queryRef ( for: request, with: resultsDataType, publisher: publisher)
129+ accessQueue. sync {
130+ let request = QueryRequest ( operationName: name, variables: variables)
131+ return operationsManager. queryRef ( for: request, with: resultsDataType, publisher: publisher)
132+ }
123133 }
124134
125135 /// Returns a Mutation Ref matching the name and specified variables.
126- public func mutation< ResultData: Decodable ,
136+ public func mutation< ResultData: Decodable & Sendable ,
127137 Variable: OperationVariable > ( name: String ,
128138 variables: Variable ,
129139 resultsDataType: ResultData
130140 . Type )
131141 -> MutationRef < ResultData ,
132142 Variable > {
133- let request = MutationRequest ( operationName: name, variables: variables)
134- return operationsManager. mutationRef ( for: request, with: resultsDataType)
143+ accessQueue. sync {
144+ let request = MutationRequest ( operationName: name, variables: variables)
145+ return operationsManager. mutationRef ( for: request, with: resultsDataType)
146+ }
135147 }
136148}
137149
138150// This enum is public so the gen sdk can access it
139151@available ( iOS 15 . 0 , macOS 12 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
140- public enum CallerSDKType {
152+ public enum CallerSDKType : Sendable {
141153 case base // base sdk is directly used
142154 case generated // generated sdk is calling the base
143155}
@@ -170,7 +182,7 @@ private class InstanceStore {
170182 autoreleaseFrequency: . workItem
171183 )
172184
173- var instances = [ InstanceKey: DataConnect] ( )
185+ private var instances = [ InstanceKey: DataConnect] ( )
174186
175187 func instance( for app: FirebaseApp , config: ConnectorConfig ,
176188 settings: DataConnectSettings , callerSDKType: CallerSDKType ) -> DataConnect {
0 commit comments