Created
May 14, 2020 00:49
-
-
Save xaphod/4f8a6402429759b6b3fd8ea2d8ea53c4 to your computer and use it in GitHub Desktop.
Using associatedtype in protocols with type erasure to have two protocols restricted to the same type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
// SINGLE VARIANT - Observer only has one thing it is watching | |
protocol IsObserver: class { | |
associatedtype DataType | |
func dataDidUpdate(_ data: [DataType]) | |
} | |
protocol HasObserver { | |
associatedtype DataType | |
static var observer: AnyHasObserver<DataType> { get } | |
} | |
class AnyHasObserver<T> { | |
typealias ObserverDataBlock = ([T])->Bool | |
var observerDataBlocks = [ObjectIdentifier:ObserverDataBlock]() | |
func addObserver<L: IsObserver>(_ observer: L) where L.DataType == T { | |
let id = ObjectIdentifier(observer) | |
self.observerDataBlocks[id] = { [weak observer] (data) in | |
guard let observer = observer else { return false } | |
observer.dataDidUpdate(data) | |
return true | |
} | |
} | |
func removeObserver<L: IsObserver>(_ observer: L) where L.DataType == T { | |
let id = ObjectIdentifier(observer) | |
self.observerDataBlocks.removeValue(forKey: id) | |
} | |
func tellObserversDataDidUpdate(_ data: [T]) { | |
WLog("HasObserver(\(T.self)) tellObserversDataDidUpdate - \(data.count) new values") | |
let keysToRemove = self.observerDataBlocks.compactMap { (key: ObjectIdentifier, value: ObserverDataBlock)->ObjectIdentifier? in | |
if value(data) { return nil } | |
return key | |
} | |
keysToRemove.forEach { self.observerDataBlocks.removeValue(forKey: $0) } | |
if keysToRemove.count > 0 { | |
WLog("HasObserver(\(T.self)) tellObserversDataDidUpdate: removed \(keysToRemove.count) dead blocks") | |
} | |
} | |
} | |
// MULTI VARIANT - Observer watching multiple types | |
protocol IsObserverOfMultipleTypes: class { | |
func dataDidUpdate(_ data: [Any], type: Any.Type) | |
} | |
protocol HasObserverOfMultipleTypes { | |
static var observer: AnyHasObserverOfMultipleTypes { get } | |
} | |
class AnyHasObserverOfMultipleTypes { | |
typealias ObserverDataBlock = ([Any], Any.Type)->Bool | |
var observerDataBlocks = [ObjectIdentifier:ObserverDataBlock]() | |
func addObserver(_ observer: IsObserverOfMultipleTypes) { | |
let id = ObjectIdentifier(observer) | |
self.observerDataBlocks[id] = { [weak observer] (data, type) in | |
guard let observer = observer else { return false } | |
observer.dataDidUpdate(data, type: type) | |
return true | |
} | |
} | |
func removeObserver(_ observer: IsObserverOfMultipleTypes) { | |
let id = ObjectIdentifier(observer) | |
self.observerDataBlocks.removeValue(forKey: id) | |
} | |
func tellObserversDataDidUpdate(_ data: [Any], type: Any.Type) { | |
WLog("HasObserverOfMultipleTypes(\(type)) tellObserversDataDidUpdate - \(data.count) new values") | |
let keysToRemove = self.observerDataBlocks.compactMap { (key: ObjectIdentifier, value: ObserverDataBlock)->ObjectIdentifier? in | |
if value(data, type) { return nil } | |
return key | |
} | |
keysToRemove.forEach { self.observerDataBlocks.removeValue(forKey: $0) } | |
if keysToRemove.count > 0 { | |
WLog("HasObserverOfMultipleTypes(\(data.self)) tellObserversDataDidUpdate: removed \(keysToRemove.count) dead blocks") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment