@@ -19,7 +19,7 @@ import Foundation
19
19
class DefaultDatafileHandler : OPTDatafileHandler {
20
20
static public var endPointStringFormat = " https://cdn.optimizely.com/datafiles/%@.json "
21
21
lazy var logger = HandlerRegistryService . shared. injectLogger ( )
22
- var timers : [ String : Timer ] = [ String: Timer] ( )
22
+ var timers : AtomicProperty < [ String : Timer ] > = AtomicProperty ( property : [ String: Timer] ( ) )
23
23
let dataStore = DataStoreUserDefaults ( )
24
24
25
25
required init ( ) {
@@ -28,34 +28,27 @@ class DefaultDatafileHandler : OPTDatafileHandler {
28
28
29
29
func downloadDatafile( sdkKey: String ) -> Data ? {
30
30
31
- let config = URLSessionConfiguration . ephemeral
32
- let session = URLSession ( configuration: config)
33
- let str = String ( format: DefaultDatafileHandler . endPointStringFormat, sdkKey)
34
- var result : Data ?
31
+ var datafile : Data ?
35
32
let group = DispatchGroup ( )
36
33
37
34
group. enter ( )
38
35
39
- if let url = URL ( string: str) {
40
- let task = session. downloadTask ( with: url) { ( url, response, error) in
41
- self . logger? . log ( level: . debug, message: response. debugDescription)
42
- if let response = response as? HTTPURLResponse , response. statusCode == 200 ,
43
- let url = url, let projectConfig = try ? Data ( contentsOf: url) {
44
- result = projectConfig
45
- self . saveDatafile ( sdkKey: sdkKey, dataFile: projectConfig)
46
- }
47
- group. leave ( )
36
+ downloadDatafile ( sdkKey: sdkKey) { ( result) in
37
+ switch result {
38
+ case . success( let data) :
39
+ datafile = data
40
+ case . failure( let error) :
41
+ self . logger? . log ( level: . error, message: error. localizedDescription)
48
42
}
49
-
50
- task. resume ( )
51
-
52
- group. wait ( )
53
-
43
+ group. leave ( )
54
44
}
55
- return result
45
+
46
+ group. wait ( )
47
+
48
+ return datafile
56
49
}
57
50
58
- open func downloadDatafile( sdkKey: String , completionHandler: @escaping ( Result < Data ? , DatafileDownloadError > ) -> Void ) {
51
+ open func downloadDatafile( sdkKey: String , completionHandler: @escaping DatafileDownloadCompletionHandler ) {
59
52
let config = URLSessionConfiguration . ephemeral
60
53
let session = URLSession ( configuration: config)
61
54
let str = String ( format: DefaultDatafileHandler . endPointStringFormat, sdkKey)
@@ -106,49 +99,59 @@ class DefaultDatafileHandler : OPTDatafileHandler {
106
99
}
107
100
108
101
func startPeriodicUpdates( sdkKey: String , updateInterval: Int , datafileChangeNotification: ( ( Data ) -> Void ) ? ) {
109
- if let _ = timers [ sdkKey] {
110
- logger? . log ( level: . info, message: " Timer already started for datafile updates " )
111
- return
102
+
103
+ timers. performAtomic { ( timers) in
104
+ if let timer = timers [ sdkKey] {
105
+ logger? . log ( level: . info, message: " Timer getting restarted for datafile updates \( sdkKey) " )
106
+ timer. invalidate ( )
107
+ timers [ sdkKey] = nil
108
+ //return
109
+ }
112
110
}
113
111
if #available( iOS 10 . 0 , tvOS 10 . 0 , * ) {
114
112
DispatchQueue . main. async {
115
- let timer = Timer . scheduledTimer ( withTimeInterval: TimeInterval ( updateInterval) , repeats: true ) { ( timer) in
116
- self . downloadDatafile ( sdkKey: sdkKey) { ( result) in
117
- if let datafileChangeNotification = datafileChangeNotification {
118
- switch result {
119
- case . success( let data) :
120
- if let data = data {
121
- datafileChangeNotification ( data)
122
- }
123
- case . failure( _) : break
124
- // don't do anything.
113
+ let timer = Timer . scheduledTimer ( withTimeInterval: TimeInterval ( updateInterval) , repeats: false ) { ( timer) in
114
+
115
+ self . downloadDatafile ( sdkKey: sdkKey, completionHandler: { ( result) in
116
+ switch result {
117
+ case . success( let data) :
118
+ if let data = data,
119
+ let datafileChangeNotification = datafileChangeNotification {
120
+ datafileChangeNotification ( data)
125
121
}
122
+ case . failure( let error) :
123
+ self . logger? . log ( level: . error, message: error. localizedDescription)
126
124
}
127
- // background download saves to cache
128
- }
125
+ self . startPeriodicUpdates ( sdkKey : sdkKey , updateInterval : updateInterval , datafileChangeNotification : datafileChangeNotification )
126
+ } )
129
127
}
130
- self . timers [ sdkKey] = timer
131
-
128
+ self . timers. performAtomic ( atomicOperation: { ( timers) in
129
+ timers [ sdkKey] = timer
130
+ } )
132
131
}
133
132
} else {
134
133
// Fallback on earlier versions
135
134
}
136
135
}
137
136
138
137
func stopPeriodicUpdates( sdkKey: String ) {
139
- if let timer = timers [ sdkKey] {
140
- logger? . log ( level: . info, message: " Stopping timer for datafile updates sdkKey: " + sdkKey)
141
-
142
- timer. invalidate ( )
143
- timers. removeValue ( forKey: sdkKey)
144
- }
138
+ timers. performAtomic { ( timers) in
139
+ if let timer = timers [ sdkKey] {
140
+ logger? . log ( level: . info, message: " Stopping timer for datafile updates sdkKey: \( sdkKey) " )
141
+
142
+ timer. invalidate ( )
143
+ timers. removeValue ( forKey: sdkKey)
144
+ }
145
145
146
+ }
146
147
}
147
148
148
149
func stopPeriodicUpdates( ) {
149
- for key in timers. keys {
150
- logger? . log ( level: . info, message: " Stopping timer for all datafile updates " )
151
- stopPeriodicUpdates ( sdkKey: key)
150
+ timers. performAtomic { ( timers) in
151
+ for key in timers. keys {
152
+ logger? . log ( level: . info, message: " Stopping timer for all datafile updates " )
153
+ stopPeriodicUpdates ( sdkKey: key)
154
+ }
152
155
}
153
156
154
157
}
0 commit comments