Skip to content

Commit a05dfb7

Browse files
committed
Refactor observations
1 parent 2a18a46 commit a05dfb7

File tree

4 files changed

+117
-162
lines changed

4 files changed

+117
-162
lines changed

Source/Shared/Storage/HybridStorage.swift

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
11
import Foundation
22

3-
protocol StorageChangeNotifier {
4-
func notifyObservers(about change: StorageChange)
5-
}
6-
7-
struct KeyChangeNotifier<T> {
8-
9-
10-
func notifyObserver(about change: KeyChange<T>, where closure: ((String) -> Bool)) {
11-
12-
}
13-
}
14-
15-
163
/// Use both memory and disk storage. Try on memory first.
174
public final class HybridStorage<T> {
185
public let memoryStorage: MemoryStorage<T>
196
public let diskStorage: DiskStorage<T>
20-
let storageObservationRegistry = ObservationRegistry<StorageChange>()
21-
let keyObservationRegistry = ObservationRegistry<KeyChange<T>>()
227

23-
var onKeyChange: ((KeyChange<T>, ((String) -> Bool)) -> Void)?
8+
private var observations = (
9+
storage: [UUID : (HybridStorage, StorageChange) -> Void](),
10+
key: [String : (HybridStorage, KeyChange<T>) -> Void]()
11+
)
2412

2513
public init(memoryStorage: MemoryStorage<T>, diskStorage: DiskStorage<T>) {
2614
self.memoryStorage = memoryStorage
@@ -32,7 +20,7 @@ public final class HybridStorage<T> {
3220
}
3321

3422
private func handleRemovedObject(at path: String) {
35-
keyObservationRegistry.notifyObserver(about: .remove) { key in
23+
notifyObserver(about: .remove) { key in
3624
let fileName = diskStorage.makeFileName(for: key)
3725
return path.contains(fileName)
3826
}
@@ -55,13 +43,13 @@ extension HybridStorage: StorageAware {
5543
memoryStorage.removeObject(forKey: key)
5644
try diskStorage.removeObject(forKey: key)
5745

58-
storageObservationRegistry.notifyAllObservers(about: .remove(key: key))
46+
notifyStorageObservers(about: .remove(key: key))
5947
}
6048

6149
public func setObject(_ object: T, forKey key: String, expiry: Expiry? = nil) throws {
6250
var keyChange: KeyChange<T>?
6351

64-
if !keyObservationRegistry.isEmpty {
52+
if observations.key[key] != nil {
6553
keyChange = .edit(before: try? self.object(forKey: key), after: object)
6654
}
6755

@@ -70,25 +58,25 @@ extension HybridStorage: StorageAware {
7058

7159

7260
if let change = keyChange {
73-
keyObservationRegistry.notifyObserver(forKey: key, about: change)
61+
notifyObserver(forKey: key, about: change)
7462
}
7563

76-
storageObservationRegistry.notifyAllObservers(about: .add(key: key))
64+
notifyStorageObservers(about: .add(key: key))
7765
}
7866

7967
public func removeAll() throws {
8068
memoryStorage.removeAll()
8169
try diskStorage.removeAll()
8270

83-
storageObservationRegistry.notifyAllObservers(about: .removeAll)
84-
keyObservationRegistry.notifyAllObservers(about: .remove)
71+
notifyStorageObservers(about: .removeAll)
72+
notifyKeyObservers(about: .remove)
8573
}
8674

8775
public func removeExpiredObjects() throws {
8876
memoryStorage.removeExpiredObjects()
8977
try diskStorage.removeExpiredObjects()
9078

91-
storageObservationRegistry.notifyAllObservers(about: .removeExpired)
79+
notifyStorageObservers(about: .removeExpired)
9280
}
9381
}
9482

@@ -102,3 +90,59 @@ public extension HybridStorage {
10290
return storage
10391
}
10492
}
93+
94+
extension HybridStorage: StorageObservationRegistry {
95+
@discardableResult
96+
public func observeStorage(using closure: @escaping (HybridStorage, StorageChange) -> Void) -> ObservationToken {
97+
let id = UUID()
98+
observations.storage[id] = closure
99+
100+
return ObservationToken { [weak self] in
101+
self?.observations.storage.removeValue(forKey: id)
102+
}
103+
}
104+
105+
public func removeAllStorageObservations() {
106+
observations.storage.removeAll()
107+
}
108+
109+
private func notifyStorageObservers(about change: StorageChange) {
110+
observations.storage.values.forEach { closure in
111+
closure(self, change)
112+
}
113+
}
114+
}
115+
116+
extension HybridStorage: KeyObservationRegistry {
117+
@discardableResult
118+
public func observeKey(_ key: String, using closure: @escaping (HybridStorage, KeyChange<T>) -> Void) -> ObservationToken {
119+
observations.key[key] = closure
120+
121+
return ObservationToken { [weak self] in
122+
self?.observations.key.removeValue(forKey: key)
123+
}
124+
}
125+
126+
public func removeObservation(forKey key: String) {
127+
observations.key.removeValue(forKey: key)
128+
}
129+
130+
public func removeAllKeyObservations() {
131+
observations.key.removeAll()
132+
}
133+
134+
private func notifyObserver(forKey key: String, about change: KeyChange<T>) {
135+
observations.key[key]?(self, change)
136+
}
137+
138+
private func notifyObserver(about change: KeyChange<T>, whereKey closure: ((String) -> Bool)) {
139+
let observation = observations.key.first { key, value in closure(key) }?.value
140+
observation?(self, change)
141+
}
142+
143+
private func notifyKeyObservers(about change: KeyChange<T>) {
144+
observations.key.values.forEach { closure in
145+
closure(self, change)
146+
}
147+
}
148+
}
Lines changed: 5 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,12 @@
11
import Foundation
22

3-
public final class KeyObservationRegistry<Storage: StorageAware> {
4-
public typealias Observation = (Storage, KeyChange<Storage.T>) -> Void
5-
private(set) var observations = [String: Observation]()
6-
var onNewKey: ((String) -> Void)?
7-
8-
public var isEmpty: Bool {
9-
return observations.isEmpty
10-
}
3+
public protocol KeyObservationRegistry {
4+
associatedtype S: StorageAware
115

126
@discardableResult
13-
public func addObservation(_ observation: @escaping Observation, forKey key: String) -> ObservationToken {
14-
observations[key] = observation
15-
onNewKey?(key)
16-
17-
return ObservationToken { [weak self] in
18-
self?.observations.removeValue(forKey: key)
19-
}
20-
}
21-
22-
public func removeObservation(forKey key: String) {
23-
observations.removeValue(forKey: key)
24-
}
25-
26-
public func removeObservation(token: ObservationToken) {
27-
token.cancel()
28-
}
29-
30-
public func removeAllObservations() {
31-
observations.removeAll()
32-
}
33-
34-
func notifyObserver(forKey key: String, about change: KeyChange<Storage.T>, in storage: Storage) {
35-
observations[key]?(storage, change)
36-
}
37-
38-
func notifyObserver(about change: KeyChange<Storage.T>,
39-
in storage: Storage,
40-
where closure: ((String) -> Bool)) {
41-
let observation = observations.first { key, value in closure(key) }?.value
42-
observation?(storage, change)
43-
}
44-
45-
func notifyAllObservers(about change: KeyChange<Storage.T>, in storage: Storage) {
46-
observations.values.forEach { closure in
47-
closure(storage, change)
48-
}
49-
}
50-
}
51-
52-
// MARK: - Notification
53-
54-
public struct KeyNotification<Storage: StorageAware> {
55-
public let change: KeyChange<Storage.T>
56-
public let storage: Storage
7+
func observeKey(_ key: String, using closure: @escaping (S, KeyChange<S.T>) -> Void) -> ObservationToken
8+
func removeObservation(forKey key: String)
9+
func removeAllKeyObservations()
5710
}
5811

5912
// MARK: - KeyChange
@@ -75,47 +28,3 @@ extension KeyChange: Equatable where T: Equatable {
7528
}
7629
}
7730
}
78-
79-
80-
81-
82-
83-
final class ObservationRegistry<Change> {
84-
typealias Observation = (Change) -> Void
85-
private(set) var observations = [String: Observation]()
86-
87-
var isEmpty: Bool {
88-
return observations.isEmpty
89-
}
90-
91-
@discardableResult
92-
func addObservation(forKey key: String = UUID().uuidString, _ observation: @escaping Observation) -> ObservationToken {
93-
observations[key] = observation
94-
return ObservationToken { [weak self] in
95-
self?.observations.removeValue(forKey: key)
96-
}
97-
}
98-
99-
func removeObservation(forKey key: String) {
100-
observations.removeValue(forKey: key)
101-
}
102-
103-
func removeAllObservations() {
104-
observations.removeAll()
105-
}
106-
107-
func notifyObserver(forKey key: String, about change: Change) {
108-
observations[key]?(change)
109-
}
110-
111-
func notifyObserver(about change: Change, where closure: ((String) -> Bool)) {
112-
let observation = observations.first { key, value in closure(key) }?.value
113-
observation?(change)
114-
}
115-
116-
func notifyAllObservers(about change: Change) {
117-
observations.values.forEach { closure in
118-
closure(change)
119-
}
120-
}
121-
}

Source/Shared/Storage/Storage.swift

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ public final class Storage<T> {
99
private let asyncStorage: AsyncStorage<T>
1010
private let hybridStorage: HybridStorage<T>
1111

12-
public let storageObservationRegistry = StorageObservationRegistry<Storage>()
13-
public let keyObservationRegistry = KeyObservationRegistry<Storage>()
14-
1512
/// Initialize storage with configuration options.
1613
///
1714
/// - Parameters:
@@ -46,16 +43,16 @@ public final class Storage<T> {
4643
public lazy var async = self.asyncStorage
4744

4845
private func subscribeToChanges(in storage: HybridStorage<T>) {
49-
storage.storageObservationRegistry.addObservation { [weak self] _, change in
50-
guard let strongSelf = self else { return }
51-
strongSelf.storageObservationRegistry.notifyObservers(about: change, in: strongSelf)
52-
}
53-
keyObservationRegistry.onNewKey = { [weak self] key in
54-
guard let strongSelf = self else { return }
55-
storage.keyObservationRegistry.addObservation({ _, change in
56-
strongSelf.keyObservationRegistry.notifyObserver(forKey: key, about: change, in: strongSelf)
57-
}, forKey: key)
58-
}
46+
// storage.storageObservationRegistry.addObservation { [weak self] _, change in
47+
// guard let strongSelf = self else { return }
48+
// strongSelf.storageObservationRegistry.notifyObservers(about: change, in: strongSelf)
49+
// }
50+
// keyObservationRegistry.onNewKey = { [weak self] key in
51+
// guard let strongSelf = self else { return }
52+
// storage.keyObservationRegistry.addObservation({ _, change in
53+
// strongSelf.keyObservationRegistry.notifyObserver(forKey: key, about: change, in: strongSelf)
54+
// }, forKey: key)
55+
// }
5956
}
6057
}
6158

@@ -86,3 +83,33 @@ public extension Storage {
8683
return Storage<U>(hybridStorage: hybridStorage.transform(transformer: transformer))
8784
}
8885
}
86+
87+
extension Storage: StorageObservationRegistry {
88+
@discardableResult
89+
public func observeStorage(using closure: @escaping (Storage, StorageChange) -> Void) -> ObservationToken {
90+
return hybridStorage.observeStorage(using: { _, change in
91+
closure(self, change)
92+
})
93+
}
94+
95+
public func removeAllStorageObservations() {
96+
hybridStorage.removeAllStorageObservations()
97+
}
98+
}
99+
100+
extension Storage: KeyObservationRegistry {
101+
@discardableResult
102+
public func observeKey(_ key: String, using closure: @escaping (Storage, KeyChange<T>) -> Void) -> ObservationToken {
103+
return hybridStorage.observeKey(key, using: { _, change in
104+
closure(self, change)
105+
})
106+
}
107+
108+
public func removeObservation(forKey key: String) {
109+
hybridStorage.removeObservation(forKey: key)
110+
}
111+
112+
public func removeAllKeyObservations() {
113+
hybridStorage.removeAllKeyObservations()
114+
}
115+
}

Source/Shared/Storage/StorageObservationRegistry.swift

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,11 @@
11
import Foundation
22

3-
public final class StorageObservationRegistry<Storage: StorageAware> {
4-
public typealias Observation = (Storage, StorageChange) -> Void
5-
private(set) var observations = [UUID: Observation]()
6-
7-
public var isEmpty: Bool {
8-
return observations.isEmpty
9-
}
3+
public protocol StorageObservationRegistry {
4+
associatedtype S: StorageAware
105

116
@discardableResult
12-
public func addObservation(_ observation: @escaping Observation) -> ObservationToken {
13-
let id = UUID()
14-
observations[id] = observation
15-
16-
return ObservationToken { [weak self] in
17-
self?.observations.removeValue(forKey: id)
18-
}
19-
}
20-
21-
public func removeObservation(token: ObservationToken) {
22-
token.cancel()
23-
}
24-
25-
public func removeAllObservations() {
26-
observations.removeAll()
27-
}
28-
29-
func notifyObservers(about change: StorageChange, in storage: Storage) {
30-
observations.values.forEach { closure in
31-
closure(storage, change)
32-
}
33-
}
7+
func observeStorage(using closure: @escaping (S, StorageChange) -> Void) -> ObservationToken
8+
func removeAllStorageObservations()
349
}
3510

3611
// MARK: - StorageChange

0 commit comments

Comments
 (0)