@@ -21,19 +21,59 @@ import Foundation
2121  case  fetched
2222} 
2323
24+ /// The AtomicConfig class for the config variables enables atomic accesses to support multiple
25+ /// namespace usage of RemoteConfig.
26+ private  class  AtomicConfig  { 
27+   private  var  value :  [ String :  [ String :  RemoteConfigValue ] ] 
28+   private  let  lock   =  NSLock ( ) 
29+ 
30+   init ( _ value:  [ String :  [ String :  RemoteConfigValue ] ] )  { 
31+     self . value =  value
32+   } 
33+ 
34+   var  wrappedValue :  [ String :  [ String :  RemoteConfigValue ] ]  { 
35+     get  {  return  load ( )  } 
36+     set  {  store ( newValue:  newValue)  } 
37+   } 
38+ 
39+   func  load( )  ->  [ String :  [ String :  RemoteConfigValue ] ]  { 
40+     lock. lock ( ) 
41+     defer  {  lock. unlock ( )  } 
42+     return  value
43+   } 
44+ 
45+   func  store( newValue:  [ String :  [ String :  RemoteConfigValue ] ] )  { 
46+     lock. lock ( ) 
47+     defer  {  lock. unlock ( )  } 
48+     value =  newValue
49+   } 
50+ 
51+   func  update( namespace:  String ,  newValue:  [ String :  RemoteConfigValue ] )  { 
52+     lock. lock ( ) 
53+     defer  {  lock. unlock ( )  } 
54+     value [ namespace]  =  newValue
55+   } 
56+ 
57+   func  update( namespace:  String ,  key:  String ,  rcValue:  RemoteConfigValue )  { 
58+     lock. lock ( ) 
59+     defer  {  lock. unlock ( )  } 
60+     value [ namespace] ? [ key]  =  rcValue
61+   } 
62+ } 
63+ 
2464/// This class handles all the config content that is fetched from the server, cached in local
2565/// config or persisted in database.
2666@objc ( RCNConfigContent)   public 
2767class  ConfigContent :  NSObject  { 
2868  /// Active config data that is currently used.
29-   private  var  _activeConfig :   [ String :   [ String :   RemoteConfigValue ] ]   =   [ : ] 
69+   private  var  _activeConfig   =   AtomicConfig ( [ : ] ) 
3070
3171  /// Pending config (aka Fetched config) data that is latest data from server that might or might
3272  /// not be applied.
33-   private  var  _fetchedConfig :   [ String :   [ String :   RemoteConfigValue ] ]   =   [ : ] 
73+   private  var  _fetchedConfig   =   AtomicConfig ( [ : ] ) 
3474
3575  /// Default config provided by user.
36-   private  var  _defaultConfig :   [ String :   [ String :   RemoteConfigValue ] ]   =   [ : ] 
76+   private  var  _defaultConfig   =   AtomicConfig ( [ : ] ) 
3777
3878  /// Active Personalization metadata that is currently used.
3979  private  var  _activePersonalization :  [ String :  Any ]  =  [ : ] 
@@ -126,9 +166,9 @@ class ConfigContent: NSObject {
126166    dbManager. loadMain ( withBundleIdentifier:  bundleIdentifier)  {  [ weak self]  success, 
127167      fetched,  active,  defaults,  rolloutMetadata in 
128168      guard  let  self =  self  else  {  return  } 
129-       self . _fetchedConfig  =   fetched
130-       self . _activeConfig  =   active
131-       self . _defaultConfig  =   defaults
169+       self . _fetchedConfig. store ( newValue :   fetched) 
170+       self . _activeConfig. store ( newValue :   active) 
171+       self . _defaultConfig. store ( newValue :   defaults) 
132172      self 
133173        . _fetchedRolloutMetadata = 
134174        rolloutMetadata [ ConfigConstants . rolloutTableKeyFetchedMetadata]  as?  [ [ String :  Any ] ]  ??  [ ] 
@@ -173,14 +213,14 @@ class ConfigContent: NSObject {
173213
174214    switch  dbSource { 
175215    case  . default: 
176-       toDictionary =  _defaultConfig 
216+       toDictionary =  defaultConfig ( ) 
177217      source =  . default
178218    case  . fetched: 
179219      RCLog . warning ( " I-RCN000008 " , 
180220                    " This shouldn't happen. Destination dictionary should never be pending type. " ) 
181221      return 
182222    case  . active: 
183-       toDictionary =  _activeConfig 
223+       toDictionary =  activeConfig ( ) 
184224      source =  . remote
185225      toDictionary. removeValue ( forKey:  firebaseNamespace) 
186226    } 
@@ -241,9 +281,9 @@ class ConfigContent: NSObject {
241281    } 
242282
243283    if  dbSource ==  . default { 
244-       _defaultConfig  =   toDictionary
284+       _defaultConfig. store ( newValue :   toDictionary) 
245285    }  else  { 
246-       _activeConfig  =   toDictionary
286+       _activeConfig. store ( newValue :   toDictionary) 
247287    } 
248288  } 
249289
@@ -307,27 +347,23 @@ class ConfigContent: NSObject {
307347  // MARK: - State Handling
308348
309349  func  handleNoChangeState( forConfigNamespace firebaseNamespace:  String )  { 
310-     if  _fetchedConfig [ firebaseNamespace]  ==  nil  { 
311-       _fetchedConfig [ firebaseNamespace]   =  [ : ] 
350+     if  fetchedConfig ( ) [ firebaseNamespace]  ==  nil  { 
351+       _fetchedConfig. update ( namespace :   firebaseNamespace,  newValue :  [ : ] ) 
312352    } 
313353  } 
314354
315355  func  handleEmptyConfigState( forConfigNamespace firebaseNamespace:  String )  { 
316-     if  let  _ =  _fetchedConfig [ firebaseNamespace]  { 
317-       _fetchedConfig [ firebaseNamespace] ? . removeAll ( ) 
318-     }  else  { 
319-       // If namespace has empty status and it doesn't exist in _fetchedConfig, we will
320-       // still add an entry for that namespace. Even if it will not be persisted in database.
321-       _fetchedConfig [ firebaseNamespace]  =  [ : ] 
322-     } 
356+     // If namespace has empty status and it doesn't exist in _fetchedConfig, we will
357+     // still add an entry for that namespace. Even if it will not be persisted in database.
358+     _fetchedConfig. update ( namespace:  firebaseNamespace,  newValue:  [ : ] ) 
323359    dbManager? . deleteRecord ( fromMainTableWithNamespace:  firebaseNamespace, 
324360                            bundleIdentifier:  bundleIdentifier, 
325361                            fromSource:  . fetched) 
326362  } 
327363
328364  func  handleNoTemplateState( forConfigNamespace firebaseNamespace:  String )  { 
329365    // Remove the namespace.
330-     _fetchedConfig. removeValue ( forKey :  firebaseNamespace) 
366+     _fetchedConfig. update ( namespace :  firebaseNamespace,  newValue :   [ : ] ) 
331367    dbManager? . deleteRecord ( fromMainTableWithNamespace:  firebaseNamespace, 
332368                            bundleIdentifier:  bundleIdentifier, 
333369                            fromSource:  . fetched) 
@@ -341,17 +377,14 @@ class ConfigContent: NSObject {
341377    dbManager? . deleteRecord ( fromMainTableWithNamespace:  firebaseNamespace, 
342378                            bundleIdentifier:  bundleIdentifier, 
343379                            fromSource:  . fetched) 
344-     if  _fetchedConfig [ firebaseNamespace]  !=  nil  { 
345-       _fetchedConfig [ firebaseNamespace] ? . removeAll ( ) 
346-     }  else  { 
347-       _fetchedConfig [ firebaseNamespace]  =  [ : ] 
348-     } 
380+     _fetchedConfig. update ( namespace:  firebaseNamespace,  newValue:  [ : ] ) 
349381
350382    // Store the fetched config values.
351383    for  (key,  value)    in  entries { 
352384      guard  let  valueData =  value. data ( using:  . utf8)  else  {  continue  } 
353-       _fetchedConfig [ firebaseNamespace] ? [ key]  =  RemoteConfigValue ( data:  valueData, 
354-                                                                   source:  . remote) 
385+       _fetchedConfig
386+         . update ( namespace:  firebaseNamespace,  key:  key, 
387+                 rcValue:  RemoteConfigValue ( data:  valueData,  source:  . remote) ) 
355388      let  values :  [ Any ]  =  [ bundleIdentifier,  firebaseNamespace,  key,  valueData] 
356389      updateMainTable ( withValues:  values,  fromSource:  . fetched) 
357390    } 
@@ -377,23 +410,23 @@ class ConfigContent: NSObject {
377410    /// If this is the first time reading the fetchedConfig, we might still be reading it from the
378411    /// database.
379412    checkAndWaitForInitialDatabaseLoad ( ) 
380-     return  _fetchedConfig
413+     return  _fetchedConfig. wrappedValue 
381414  } 
382415
383416  @objc   public 
384-   func  activeConfig( )  ->  [ String :  Any ]  { 
417+   func  activeConfig( )  ->  [ String :  [ String :   RemoteConfigValue ] ]  { 
385418    /// If this is the first time reading the activeConfig, we might still be reading it from the
386419    /// database.
387420    checkAndWaitForInitialDatabaseLoad ( ) 
388-     return  _activeConfig
421+     return  _activeConfig. wrappedValue 
389422  } 
390423
391424  @objc   public 
392-   func  defaultConfig( )  ->  [ String :  Any ]  { 
425+   func  defaultConfig( )  ->  [ String :  [ String :   RemoteConfigValue ] ]  { 
393426    /// If this is the first time reading the defaultConfig, we might still be reading it from the
394427    /// database.
395428    checkAndWaitForInitialDatabaseLoad ( ) 
396-     return  _defaultConfig
429+     return  _defaultConfig. wrappedValue 
397430  } 
398431
399432  @objc   public 
@@ -420,7 +453,7 @@ class ConfigContent: NSObject {
420453    // database.
421454    checkAndWaitForInitialDatabaseLoad ( ) 
422455    return  [ 
423-       ConfigConstants . fetchResponseKeyEntries:  _activeConfig [ firebaseNamespace]  as  Any , 
456+       ConfigConstants . fetchResponseKeyEntries:  activeConfig ( ) [ firebaseNamespace]  as  Any , 
424457      ConfigConstants . fetchResponseKeyPersonalizationMetadata:  activePersonalization, 
425458    ] 
426459  } 
@@ -431,8 +464,8 @@ class ConfigContent: NSObject {
431464    // TODO: handle diff in experiment metadata.
432465    var  updatedKeys  =  Set < String > ( ) 
433466
434-     let  fetchedConfig  =  _fetchedConfig [ firebaseNamespace]  ??  [ : ] 
435-     let  activeConfig  =  _activeConfig [ firebaseNamespace]  ??  [ : ] 
467+     let  fetchedConfig  =  fetchedConfig ( ) [ firebaseNamespace]  ??  [ : ] 
468+     let  activeConfig  =  activeConfig ( ) [ firebaseNamespace]  ??  [ : ] 
436469    let  fetchedP13n  =  _fetchedPersonalization
437470    let  activeP13n  =  _activePersonalization
438471    let  fetchedRolloutMetadata  =  _fetchedRolloutMetadata
0 commit comments