Skip to content

Commit 8b0f324

Browse files
fix (OPTDataStore): Remove print statements and change memory store default backing store. (#310)
1 parent 7286fe6 commit 8b0f324

File tree

16 files changed

+322
-154
lines changed

16 files changed

+322
-154
lines changed

OptimizelySwiftSDK.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1678,6 +1678,7 @@
16781678
6E14CD642423F80B00010234 /* OptimizelyTests-Batch-iOS */ = {
16791679
isa = PBXGroup;
16801680
children = (
1681+
6E75198D22C5211100B2B157 /* EventDispatcherTests_Batch.swift */,
16811682
);
16821683
path = "OptimizelyTests-Batch-iOS";
16831684
sourceTree = "<group>";
@@ -1945,7 +1946,6 @@
19451946
6E75198A22C5211100B2B157 /* BucketTests_Base.swift */,
19461947
6E75198B22C5211100B2B157 /* NotificationCenterTests.swift */,
19471948
6E75198C22C5211100B2B157 /* BucketTests_ExpToVariation.swift */,
1948-
6E75198D22C5211100B2B157 /* EventDispatcherTests_Batch.swift */,
19491949
6E75198E22C5211100B2B157 /* LoggerTests.swift */,
19501950
6E75198F22C5211100B2B157 /* BucketTests_BucketVariation.swift */,
19511951
6E75199022C5211100B2B157 /* DecisionListenerTests.swift */,

Sources/Customization/DefaultEventDispatcher.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ public enum DataStoreType {
2222

2323
open class DefaultEventDispatcher: BackgroundingCallbacks, OPTEventDispatcher {
2424

25-
static let sharedInstance = DefaultEventDispatcher()
25+
#if os(tvOS)
26+
static let sharedInstance =
27+
DefaultEventDispatcher(backingStore: .memory)
28+
#else
29+
static let sharedInstance =
30+
DefaultEventDispatcher()
31+
#endif
2632

2733
// timer-interval for batching (0 = no batching, negative = use default)
2834
var timerInterval: TimeInterval
Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2019, Optimizely, Inc. and contributors *
2+
* Copyright 2019-2020, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -21,21 +21,16 @@ import Foundation
2121
public class DataStoreFile<T>: OPTDataStore where T: Codable {
2222
let dataStoreName: String
2323
let lock: DispatchQueue
24-
let url: URL
24+
let async: Bool
25+
public let url: URL
26+
lazy var logger: OPTLogger? = OPTLoggerFactory.getLogger()
2527

26-
init(storeName: String) {
28+
init(storeName: String, async: Bool = true) {
29+
self.async = async
2730
dataStoreName = storeName
2831
lock = DispatchQueue(label: storeName)
2932
if let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
3033
self.url = url.appendingPathComponent(storeName, isDirectory: false)
31-
if !FileManager.default.fileExists(atPath: self.url.path) {
32-
do {
33-
let data = try JSONEncoder().encode([Data]())
34-
try data.write(to: self.url, options: .atomicWrite)
35-
} catch let error {
36-
print(error.localizedDescription)
37-
}
38-
}
3934
} else {
4035
self.url = URL(fileURLWithPath: storeName)
4136
}
@@ -47,26 +42,63 @@ public class DataStoreFile<T>: OPTDataStore where T: Codable {
4742
lock.sync {
4843
do {
4944
let contents = try Data(contentsOf: self.url)
50-
let item = try JSONDecoder().decode(T.self, from: contents)
51-
returnItem = item
52-
} catch let errorr {
53-
print(errorr.localizedDescription)
45+
if type(of: T.self) == type(of: Data.self) {
46+
returnItem = contents as? T
47+
} else {
48+
let item = try JSONDecoder().decode(T.self, from: contents)
49+
returnItem = item
50+
}
51+
} catch let e as NSError {
52+
if e.code != 260 {
53+
self.logger?.e(e.localizedDescription)
54+
}
5455
}
5556
}
5657

5758
return returnItem
5859
}
5960

61+
func doCall(async: Bool, block:@escaping () -> Void) {
62+
if async {
63+
lock.async {
64+
block()
65+
}
66+
} else {
67+
lock.sync {
68+
block()
69+
}
70+
}
71+
}
72+
6073
public func saveItem(forKey: String, value: Any) {
61-
lock.async {
74+
doCall(async: self.async) {
6275
do {
6376
if let value = value as? T {
64-
let data = try JSONEncoder().encode(value)
65-
try data.write(to: self.url, options: .atomic)
77+
var data: Data?
78+
// don't bother to convert... otherwise, do
79+
if let value = value as? Data {
80+
data = value
81+
} else {
82+
data = try JSONEncoder().encode(value)
83+
}
84+
if let data = data {
85+
try data.write(to: self.url, options: .atomic)
86+
}
6687
}
67-
} catch let error {
68-
print(error.localizedDescription)
88+
} catch let e {
89+
self.logger?.e(e.localizedDescription)
90+
}
91+
}
92+
}
93+
94+
public func removeItem(forKey: String) {
95+
doCall(async: self.async) {
96+
do {
97+
try FileManager.default.removeItem(at: self.url)
98+
} catch let e {
99+
self.logger?.e(e.localizedDescription)
69100
}
70101
}
102+
71103
}
72104
}

Sources/Implementation/Datastore/DataStoreMemory.swift

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2019, Optimizely, Inc. and contributors *
2+
* Copyright 2019-2020, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -22,26 +22,15 @@ import Foundation
2222
public class DataStoreMemory<T>: BackgroundingCallbacks, OPTDataStore where T: Codable {
2323
let dataStoreName: String
2424
let lock: DispatchQueue
25-
let url: URL
2625
var data: T?
26+
var backupDataStore: OPTDataStore
27+
lazy var logger: OPTLogger? = OPTLoggerFactory.getLogger()
2728

28-
init(storeName: String) {
29+
init(storeName: String, backupStore: OPTDataStore = DataStoreUserDefaults()) {
2930
dataStoreName = storeName
3031
lock = DispatchQueue(label: storeName)
31-
if let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
32-
self.url = url.appendingPathComponent(storeName, isDirectory: false)
33-
if !FileManager.default.fileExists(atPath: self.url.path) {
34-
do {
35-
let data = try JSONEncoder().encode([Data]())
36-
try data.write(to: self.url, options: .atomicWrite)
37-
} catch let error {
38-
print(error.localizedDescription)
39-
}
40-
}
41-
} else {
42-
self.url = URL(fileURLWithPath: storeName)
43-
}
44-
32+
backupDataStore = backupStore
33+
load(forKey: dataStoreName)
4534
subscribe()
4635
}
4736

@@ -50,22 +39,22 @@ public class DataStoreMemory<T>: BackgroundingCallbacks, OPTDataStore where T: C
5039
}
5140

5241
public func getItem(forKey: String) -> Any? {
53-
var returnData: T?
54-
42+
var retVal: T?
5543
lock.sync {
56-
returnData = data
44+
retVal = self.data
5745
}
58-
return returnData
46+
return retVal
5947
}
6048

6149
public func load(forKey: String) {
6250
lock.sync {
6351
do {
64-
let contents = try Data(contentsOf: self.url)
65-
let item = try JSONDecoder().decode(T.self, from: contents)
66-
self.data = item
67-
} catch let errorr {
68-
print(errorr.localizedDescription)
52+
if let contents = backupDataStore.getItem(forKey: dataStoreName) as? Data {
53+
let item = try JSONDecoder().decode(T.self, from: contents)
54+
self.data = item
55+
}
56+
} catch let error {
57+
self.logger?.e(error.localizedDescription)
6958
}
7059
}
7160
}
@@ -77,17 +66,18 @@ public class DataStoreMemory<T>: BackgroundingCallbacks, OPTDataStore where T: C
7766
}
7867
}
7968
}
69+
70+
public func removeItem(forKey: String) {
71+
lock.async {
72+
self.data = nil
73+
self.backupDataStore.removeItem(forKey: forKey)
74+
}
75+
// this is a no op here. data could be niled out.
76+
}
8077

8178
func save(forKey: String, value: Any) {
8279
lock.async {
83-
do {
84-
if let value = value as? T {
85-
let data = try JSONEncoder().encode(value)
86-
try data.write(to: self.url, options: .atomic)
87-
}
88-
} catch let error {
89-
print(error.localizedDescription)
90-
}
80+
self.backupDataStore.saveItem(forKey: forKey, value: value)
9181
}
9282
}
9383

Sources/Implementation/Datastore/DataStoreUserDefaults.swift

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2019, Optimizely, Inc. and contributors *
2+
* Copyright 2019-2020, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -19,7 +19,14 @@ import Foundation
1919
/// Implementation of OPTDataStore using standard UserDefaults.
2020
/// This class should be used as a singleton.
2121
public class DataStoreUserDefaults: OPTDataStore {
22+
// A hardcoded max for user defaults. Since there is a max on iostv
23+
#if os(tvOS)
24+
static let MAX_DS_SIZE = 128000
25+
#else
26+
static let MAX_DS_SIZE = 1000000
27+
#endif
2228
static let dispatchQueue = DispatchQueue(label: "OPTDataStoreQueueUserDefaults")
29+
lazy var logger: OPTLogger = OPTLoggerFactory.getLogger()
2330

2431
public func getItem(forKey: String) -> Any? {
2532

@@ -29,10 +36,44 @@ public class DataStoreUserDefaults: OPTDataStore {
2936
}
3037

3138
public func saveItem(forKey: String, value: Any) {
39+
3240
DataStoreUserDefaults.dispatchQueue.async {
41+
if let value = value as? Data {
42+
if value.count > DataStoreUserDefaults.MAX_DS_SIZE {
43+
self.logger.e("Save to User Defaults error: \(forKey) is too big to save size(\(value.count))")
44+
return
45+
}
46+
} else if let value = value as? String {
47+
if value.count > DataStoreUserDefaults.MAX_DS_SIZE {
48+
self.logger.e("Save to User Defaults error: \(forKey) is too big to save size(\(value.count))")
49+
return
50+
}
51+
} else if let value = value as? [Data] {
52+
var l: Int = 0
53+
l = value.reduce(into: l, { (res, data) in
54+
res += data.count
55+
})
56+
if l > DataStoreUserDefaults.MAX_DS_SIZE {
57+
self.logger.e("Save to User Defaults error: \(forKey) is too big to save size(\(value.count))")
58+
return
59+
}
60+
} else if let value = value as? [String] {
61+
var l: Int = 0
62+
l = value.reduce(into: l, { (res, data) in
63+
res += data.count
64+
})
65+
if l > DataStoreUserDefaults.MAX_DS_SIZE {
66+
self.logger.e("Save to User Defaults error: \(forKey) is too big to save size(\(value.count))")
67+
return
68+
}
69+
}
3370
UserDefaults.standard.set(value, forKey: forKey)
3471
UserDefaults.standard.synchronize()
3572
}
3673
}
3774

75+
public func removeItem(forKey: String) {
76+
UserDefaults.standard.removeObject(forKey: forKey)
77+
}
78+
3879
}

0 commit comments

Comments
 (0)