Implement store observations

This commit is contained in:
Vadym Markov
2018-08-02 16:02:46 +02:00
parent 34db39445f
commit e42cbc06ff
4 changed files with 66 additions and 0 deletions
+16
View File
@@ -135,6 +135,12 @@
D5A138C11EB29BFA00881A20 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A138C01EB29BFA00881A20 /* UIImage+Extensions.swift */; };
D5A138C21EB29BFA00881A20 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A138C01EB29BFA00881A20 /* UIImage+Extensions.swift */; };
D5A138C41EB29C2100881A20 /* NSImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A138C31EB29C2100881A20 /* NSImage+Extensions.swift */; };
D5A9D1B721134547005DBD3F /* ObservationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9D1B621134547005DBD3F /* ObservationToken.swift */; };
D5A9D1B821134547005DBD3F /* ObservationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9D1B621134547005DBD3F /* ObservationToken.swift */; };
D5A9D1B921134547005DBD3F /* ObservationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9D1B621134547005DBD3F /* ObservationToken.swift */; };
D5A9D1BB211345D4005DBD3F /* Dictionary+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9D1BA211345D4005DBD3F /* Dictionary+Extensions.swift */; };
D5A9D1BC211345D4005DBD3F /* Dictionary+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9D1BA211345D4005DBD3F /* Dictionary+Extensions.swift */; };
D5A9D1BD211345D4005DBD3F /* Dictionary+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9D1BA211345D4005DBD3F /* Dictionary+Extensions.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -222,6 +228,8 @@
D5643E361C43F2CC00582E17 /* Storage.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Storage.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
D5A138C01EB29BFA00881A20 /* UIImage+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extensions.swift"; sourceTree = "<group>"; };
D5A138C31EB29C2100881A20 /* NSImage+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSImage+Extensions.swift"; sourceTree = "<group>"; };
D5A9D1B621134547005DBD3F /* ObservationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservationToken.swift; sourceTree = "<group>"; };
D5A9D1BA211345D4005DBD3F /* Dictionary+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Extensions.swift"; sourceTree = "<group>"; };
D5DC59E01C20593E003BD79B /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EBAACA991FBC369300FA206E /* SimpleStorage.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = SimpleStorage.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
/* End PBXFileReference section */
@@ -310,6 +318,7 @@
children = (
D28897041F8B79B300C61DEE /* JSONDecoder+Extensions.swift */,
D2CF98501F694FFA00CE8F68 /* Date+Extensions.swift */,
D5A9D1BA211345D4005DBD3F /* Dictionary+Extensions.swift */,
);
path = Extensions;
sourceTree = "<group>";
@@ -333,6 +342,7 @@
D270148F20D1251E003B45C7 /* TypeWrapper.swift */,
D270149320D125AC003B45C7 /* MemoryCapsule.swift */,
D27014A420D129EB003B45C7 /* TransformerFactory.swift */,
D5A9D1B621134547005DBD3F /* ObservationToken.swift */,
);
path = Library;
sourceTree = "<group>";
@@ -806,12 +816,14 @@
D270147220D1018A003B45C7 /* Transformer.swift in Sources */,
D21B668C1F6A723C00125DE1 /* Types.swift in Sources */,
D2D4CC261FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */,
D5A9D1BD211345D4005DBD3F /* Dictionary+Extensions.swift in Sources */,
D27014A720D129EB003B45C7 /* TransformerFactory.swift in Sources */,
D270147E20D107DA003B45C7 /* SyncStorage.swift in Sources */,
D292DAFF1F6A970B0060F614 /* Result.swift in Sources */,
D21B669A1F6A724300125DE1 /* Date+Extensions.swift in Sources */,
D21B66891F6A723C00125DE1 /* ImageWrapper.swift in Sources */,
D21B668B1F6A723C00125DE1 /* StorageError.swift in Sources */,
D5A9D1B921134547005DBD3F /* ObservationToken.swift in Sources */,
D270148A20D11040003B45C7 /* Storage+Transform.swift in Sources */,
D5A138C21EB29BFA00881A20 /* UIImage+Extensions.swift in Sources */,
D21B66851F6A723C00125DE1 /* DataSerializer.swift in Sources */,
@@ -887,12 +899,14 @@
D270147120D1018A003B45C7 /* Transformer.swift in Sources */,
D21B66831F6A723C00125DE1 /* Types.swift in Sources */,
D2D4CC251FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */,
D5A9D1BC211345D4005DBD3F /* Dictionary+Extensions.swift in Sources */,
D27014A620D129EB003B45C7 /* TransformerFactory.swift in Sources */,
D270147D20D107DA003B45C7 /* SyncStorage.swift in Sources */,
D292DAFE1F6A970B0060F614 /* Result.swift in Sources */,
D21B66991F6A724200125DE1 /* Date+Extensions.swift in Sources */,
D21B66801F6A723C00125DE1 /* ImageWrapper.swift in Sources */,
D21B66821F6A723C00125DE1 /* StorageError.swift in Sources */,
D5A9D1B821134547005DBD3F /* ObservationToken.swift in Sources */,
D270148920D11040003B45C7 /* Storage+Transform.swift in Sources */,
D5A138C41EB29C2100881A20 /* NSImage+Extensions.swift in Sources */,
D21B667C1F6A723C00125DE1 /* DataSerializer.swift in Sources */,
@@ -937,12 +951,14 @@
D2CF98601F694FFA00CE8F68 /* DiskConfig.swift in Sources */,
D270147020D1018A003B45C7 /* Transformer.swift in Sources */,
D292DAFD1F6A970B0060F614 /* Result.swift in Sources */,
D5A9D1BB211345D4005DBD3F /* Dictionary+Extensions.swift in Sources */,
D27014A520D129EB003B45C7 /* TransformerFactory.swift in Sources */,
D2D4CC241FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */,
D270147C20D107DA003B45C7 /* SyncStorage.swift in Sources */,
D2CF98671F694FFA00CE8F68 /* Expiry.swift in Sources */,
D270148820D11040003B45C7 /* Storage+Transform.swift in Sources */,
D2CF986A1F694FFA00CE8F68 /* StorageError.swift in Sources */,
D5A9D1B721134547005DBD3F /* ObservationToken.swift in Sources */,
D5A138C11EB29BFA00881A20 /* UIImage+Extensions.swift in Sources */,
D270147820D1046A003B45C7 /* HybridStorage.swift in Sources */,
D270148420D10E76003B45C7 /* AsyncStorage.swift in Sources */,
@@ -0,0 +1,9 @@
import Foundation
extension Dictionary where Key == UUID {
mutating func insert(_ value: Value) -> UUID {
let id = UUID()
self[id] = value
return id
}
}
@@ -0,0 +1,11 @@
final class ObservationToken {
private let cancellationClosure: () -> Void
init(cancellationClosure: @escaping () -> Void) {
self.cancellationClosure = cancellationClosure
}
func cancel() {
cancellationClosure()
}
}
+30
View File
@@ -1,6 +1,13 @@
import Foundation
import Dispatch
enum StoreChange {
case addition
case singleDeletion
case allDeletion
case expiredDeletion
}
/// Manage storage. Use memory storage if specified.
/// Synchronous by default. Use `async` for asynchronous operations.
public class Storage<T> {
@@ -8,6 +15,17 @@ public class Storage<T> {
let syncStorage: SyncStorage<T>
let asyncStorage: AsyncStorage<T>
private var observations = [UUID : (Storage, StoreChange) -> Void]()
@discardableResult
func observeChanges(using closure: @escaping (Storage, StoreChange) -> Void) -> ObservationToken {
let id = observations.insert(closure)
return ObservationToken { [weak self] in
self?.observations.removeValue(forKey: id)
}
}
/// Initialize storage with configuration options.
///
/// - Parameters:
@@ -56,14 +74,26 @@ extension Storage: StorageAware {
public func setObject(_ object: T, forKey key: String, expiry: Expiry? = nil) throws {
try self.syncStorage.setObject(object, forKey: key, expiry: expiry)
notifyObservers(of: .addition)
}
public func removeAll() throws {
try self.syncStorage.removeAll()
notifyObservers(of: .allDeletion)
}
public func removeExpiredObjects() throws {
try self.syncStorage.removeExpiredObjects()
notifyObservers(of: .expiredDeletion)
}
private func notifyObservers(of change: StoreChange) {
observations.values.forEach { [weak self] closure in
guard let strongSelf = self else {
return
}
closure(strongSelf, change)
}
}
}