Last active
August 29, 2015 14:26
-
-
Save mxpr/9f98d1fd6c314897dff0 to your computer and use it in GitHub Desktop.
KeyedCallbacks
This file contains 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
protocol KeyValueStore | |
{ | |
func valueForKey(key: String) -> String | |
func setValue(value: String, forKey key: String) | |
func removeValueForKey(key: String) | |
} |
This file contains 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
class DictionaryKeyValueStore : KeyValueStore | |
{ | |
private var store = [String : String]() | |
// MARK: KeyValueStore | |
func valueForKey(key: String) -> String? | |
{ | |
return store[key] | |
} | |
func setValue(value: String, forKey key: String) | |
{ | |
store[key] = value | |
} | |
func removeValueForKey(key: String) | |
{ | |
store.removeValueForKey(key) | |
} | |
} |
This file contains 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
protocol KeyValueStore | |
{ | |
func valueForKey(key: String) -> String | |
func setValue(value: String, forKey key: String) | |
func removeValueForKey(key: String) | |
func registerForUpdates(key: String, callback: (key: String, newValue:String)->Void) | |
} |
This file contains 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
class DictionaryKeyValueStore : KeyValueStore | |
{ | |
typealias UpdatesCallback = (key: String, newValue:String?)->Void | |
private var store = [String : String]() | |
private var keyedCallbacks = [String: [UpdatesCallback]]() | |
// MARK: KeyValueStore | |
func valueForKey(key: String) -> String? | |
{ | |
return store[key] | |
} | |
func setValue(value: String, forKey key: String) | |
{ | |
store[key] = value | |
notifyChanges(key, newValue: value) | |
} | |
func removeValueForKey(key: String) | |
{ | |
store.removeValueForKey(key) | |
notifyChanges(key, newValue: nil) | |
} | |
func registerForUpdates(key: String, callback: UpdatesCallback) | |
{ | |
if var keyCallbacks = keyedCallbacks[key] | |
{ | |
keyCallbacks.append(callback) | |
keyedCallbacks[key] = keyCallbacks | |
} | |
else | |
{ | |
keyedCallbacks[key] = [callback] | |
} | |
} | |
// MARK: Private | |
private func notifyChanges(key: String, newValue: String?) | |
{ | |
if let keyCallbacks = keyedCallbacks[key] | |
{ | |
for callback in keyCallbacks | |
{ | |
callback(key: key, newValue: newValue) | |
} | |
} | |
} | |
} |
This file contains 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
class KeyedCallbacks<CallbackParameters> | |
{ | |
typealias Callback = (CallbackParameters) -> Void | |
private var keyedCallbacks = [String: [Callback]]() | |
func register(key: String, callback: Callback) | |
{ | |
if var keyCallbacks = keyedCallbacks[key] | |
{ | |
keyCallbacks.append(callback) | |
keyedCallbacks[key] = keyCallbacks | |
} | |
else | |
{ | |
keyedCallbacks[key] = [callback] | |
} | |
} | |
func performCallbacksForKey(key:String, withParameters parameters: CallbackParameters) | |
{ | |
if let keyCallbacks = keyedCallbacks[key] | |
{ | |
for callback in keyCallbacks | |
{ | |
callback(parameters) | |
} | |
} | |
} | |
} |
This file contains 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
class DictionaryKeyValueStore : KeyValueStore | |
{ | |
typealias CallbackParameters = (key: String, newValue:String?) | |
typealias UpdatesCallback = CallbackParameters->Void | |
private var store = [String : String]() | |
private var keyedCallbacks = KeyedCallbacks<CallbackParameters>() | |
// MARK: KeyValueStore | |
func valueForKey(key: String) -> String? | |
{ | |
return store[key] | |
} | |
func setValue(value: String, forKey key: String) | |
{ | |
store[key] = value | |
notifyChanges(key, newValue: value) | |
} | |
func removeValueForKey(key: String) | |
{ | |
store.removeValueForKey(key) | |
notifyChanges(key, newValue: nil) | |
} | |
func registerForUpdates(key: String, callback: UpdatesCallback) | |
{ | |
keyedCallbacks.register(key , callback: callback) | |
} | |
// MARK: Private | |
private func notifyChanges(key: String, newValue: String?) | |
{ | |
keyedCallbacks.performCallbacksForKey(key, withParameters: (key: key, newValue: newValue )) | |
} | |
} |
This file contains 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
func deregister(key: String, callback: Callback) | |
{ | |
if var keyCallbacks = keyedCallbacks[key], | |
index = keyCallbacks.indexOf(callback) // This does not work! | |
{ | |
keyCallbacks.removeAtIndex(index) | |
if keyCallbacks.count > 0 | |
{ | |
keyedCallbacks[key] = keyCallbacks | |
} | |
else | |
{ | |
keyedCallbacks.removeValueForKey(key) | |
} | |
} | |
} |
This file contains 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
protocol CallbackHandle | |
{ | |
} | |
// .. | |
func register(key: String, callback: Callback) -> CallbackHandle | |
func deregister(handle: CallbackHandle) | |
// .. |
This file contains 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
public protocol CallbackHandle | |
{ | |
} | |
private class KeyedCallbackHandle<CallbackParameters> : CallbackHandle, Equatable | |
{ | |
typealias Callback = (CallbackParameters) -> Void | |
let key: String | |
let callback : Callback | |
init(key: String, callback: Callback) | |
{ | |
self.key = key | |
self.callback = callback | |
} | |
} | |
private func ==<T>(lhs: KeyedCallbackHandle<T>, rhs: KeyedCallbackHandle<T>) -> Bool | |
{ | |
return lhs === rhs | |
} | |
public class KeyedCallbacks<CallbackParameters> | |
{ | |
typealias Callback = (CallbackParameters) -> Void | |
private var keyedHandles = [String: [KeyedCallbackHandle<CallbackParameters>]]() | |
public init() | |
{ | |
} | |
public func register(key: String, callback: Callback) -> CallbackHandle | |
{ | |
let handle = KeyedCallbackHandle<CallbackParameters>(key:key, callback:callback) | |
if var handles = keyedHandles[key] | |
{ | |
handles.append(handle) | |
keyedHandles[key] = handles | |
} | |
else | |
{ | |
keyedHandles[key] = [handle] | |
} | |
return handle | |
} | |
public func deregister(handle: CallbackHandle) | |
{ | |
if let keyedCallbackHandle = handle as? KeyedCallbackHandle<CallbackParameters>, | |
var handles = keyedHandles[keyedCallbackHandle.key], | |
let index = handles.indexOf(keyedCallbackHandle) | |
{ | |
handles.removeAtIndex(index) | |
if handles.count > 0 | |
{ | |
keyedHandles[keyedCallbackHandle.key] = handles | |
} | |
else | |
{ | |
keyedHandles.removeValueForKey(keyedCallbackHandle.key) | |
} | |
} | |
} | |
public func performCallbacksForKey(key:String, withParameters parameters: CallbackParameters) | |
{ | |
if let handles = keyedHandles[key] | |
{ | |
for handle in handles | |
{ | |
handle.callback(parameters) | |
} | |
} | |
} | |
} |
This file contains 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
private class KeyedCallbackHandle<CallbackParameters> : CallbackHandle, Equatable | |
{ | |
typealias Callback = (CallbackParameters) -> Void | |
let key: String | |
let callback : Callback | |
var onDeinit : (()->Void)? | |
init(key: String, callback: Callback) | |
{ | |
self.key = key | |
self.callback = callback | |
} | |
deinit | |
{ | |
onDeinit?() | |
} | |
} |
This file contains 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
// .. | |
public func register(key: String, callback: Callback) -> CallbackHandle | |
{ | |
let handle = KeyedCallbackHandle<CallbackParameters>(key:key, callback:callback) | |
handle.onDeinit = { [weak self, weak handle] in | |
if let s = self, let h = handle | |
{ | |
s.deregister(h) | |
} | |
} | |
if var handles = keyedHandles[key] | |
{ | |
handles.append(handle) | |
keyedHandles[key] = handles | |
} | |
else | |
{ | |
keyedHandles[key] = [handle] | |
} | |
return handle | |
} | |
// .. |
This file contains 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
private class WeakKeyedCallbackHandle<CallbackParameters> : Equatable | |
{ | |
weak var handle : KeyedCallbackHandle<CallbackParameters>? | |
init(_ handle: KeyedCallbackHandle<CallbackParameters>) | |
{ | |
self.handle = handle | |
} | |
} | |
private func ==<T>(lhs: WeakKeyedCallbackHandle<T>, rhs: WeakKeyedCallbackHandle<T>) -> Bool | |
{ | |
return lhs.handle == rhs.handle | |
} |
This file contains 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
public class KeyedCallbacks<CallbackParameters> | |
{ | |
typealias Callback = (CallbackParameters) -> Void | |
private var keyedHandles = [String: [WeakKeyedCallbackHandle<CallbackParameters>]]() | |
public init() | |
{ | |
} | |
public func register(key: String, callback: Callback) -> CallbackHandle | |
{ | |
let handle = KeyedCallbackHandle<CallbackParameters>(key:key, callback:callback) | |
handle.onDeinit = { [weak self, weak handle] in | |
if let s = self, let h = handle | |
{ | |
s.deregister(h) | |
} | |
} | |
let weakHandle = WeakKeyedCallbackHandle(handle) | |
if var handles = keyedHandles[key] | |
{ | |
handles.append(weakHandle) | |
keyedHandles[key] = handles | |
} | |
else | |
{ | |
keyedHandles[key] = [weakHandle] | |
} | |
return handle | |
} | |
public func deregister(handle: CallbackHandle) | |
{ | |
if let keyedCallbackHandle = handle as? KeyedCallbackHandle<CallbackParameters>, | |
var handles = keyedHandles[keyedCallbackHandle.key], | |
let index = handles.indexOf(WeakKeyedCallbackHandle(handle)) | |
{ | |
handles.removeAtIndex(index) | |
if handles.count > 0 | |
{ | |
keyedHandles[keyedCallbackHandle.key] = handles | |
} | |
else | |
{ | |
keyedHandles.removeValueForKey(keyedCallbackHandle.key) | |
} | |
} | |
} | |
public func performCallbacksForKey(key:String, withParameters parameters: CallbackParameters) | |
{ | |
if let weakHandles = keyedHandles[key] | |
{ | |
for weakHandle in weakHandles | |
{ | |
weakHandle.handle?.callback(parameters) | |
} | |
} | |
} | |
} |
This file contains 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
private class KeyedCallbackHandles<CallbackParameters> | |
{ | |
private var keyedHandles = [String: [WeakKeyedCallbackHandle<CallbackParameters>]]() | |
func add(handle: KeyedCallbackHandle<CallbackParameters>) | |
{ | |
handle.onDeinit = { [weak self, weak handle] in | |
if let s = self, let h = handle | |
{ | |
s.remove(h) | |
} | |
} | |
let weakHandle = WeakKeyedCallbackHandle(handle) | |
if var handles = keyedHandles[handle.key] | |
{ | |
handles.append(weakHandle) | |
keyedHandles[handle.key] = handles | |
} | |
else | |
{ | |
keyedHandles[handle.key] = [weakHandle] | |
} | |
} | |
func remove(handle: KeyedCallbackHandle<CallbackParameters>) | |
{ | |
if var handles = keyedHandles[handle.key], | |
let index = handles.indexOf(WeakKeyedCallbackHandle(handle)) | |
{ | |
handles.removeAtIndex(index) | |
if handles.count > 0 | |
{ | |
keyedHandles[handle.key] = handles | |
} | |
else | |
{ | |
keyedHandles.removeValueForKey(handle.key) | |
} | |
} | |
} | |
func handlesForKey(key: String) -> [KeyedCallbackHandle<CallbackParameters>]? | |
{ | |
var handles : [KeyedCallbackHandle<CallbackParameters>]? | |
if let weakHandles = keyedHandles[key] | |
{ | |
handles = weakHandles.flatMap({ $0.handle }) | |
} | |
return handles | |
} | |
} | |
public class KeyedCallbacks<CallbackParameters> | |
{ | |
typealias Callback = (CallbackParameters) -> Void | |
private var keyedHandles = KeyedCallbackHandles<CallbackParameters>() | |
public init() | |
{ | |
} | |
public func register(key: String, callback: Callback) -> CallbackHandle | |
{ | |
let handle = KeyedCallbackHandle<CallbackParameters>(key:key, callback:callback) | |
keyedHandles.add(handle) | |
return handle | |
} | |
public func deregister(handle: CallbackHandle) | |
{ | |
if let keyedCallbackHandle = handle as? KeyedCallbackHandle<CallbackParameters> | |
{ | |
keyedHandles.remove(keyedCallbackHandle) | |
} | |
} | |
public func performCallbacksForKey(key:String, withParameters parameters: CallbackParameters) | |
{ | |
if let handles = keyedHandles.handlesForKey(key) | |
{ | |
for handle in handles | |
{ | |
handle.callback(parameters) | |
} | |
} | |
} | |
} |
This file contains 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
// .. | |
class DictionaryKeyValueStore : KeyValueStore | |
{ | |
// .. | |
private var keyedCallbacks = KeyedCallbacks<CallbackParameters>() | |
// .. | |
func registerForUpdates(key: String, callback: UpdatesCallback) -> CallbackHandle | |
{ | |
return keyedCallbacks.register(key , callback: callback) | |
} | |
// .. | |
} | |
// .. |
This file contains 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
public func usage() | |
{ | |
let keyValueStore = DictionaryKeyValueStore() | |
let handle1 = keyValueStore.registerForUpdates("a") { print(" ## \($0)") } | |
unused(handle1) | |
do | |
{ | |
let handle2 = keyValueStore.registerForUpdates("a") { print(" >> \($0)") } | |
unused(handle2) | |
keyValueStore.setValue("cool!", forKey: "a") | |
//prints | |
// | |
// ## ("a", Optional("cool!")) | |
// >> ("a", Optional("cool!")) | |
} | |
keyValueStore.setValue("warmer", forKey: "a") | |
//prints | |
// | |
// ## ("a", Optional("warmer")) | |
} | |
public func unused(_ : Any) | |
{ | |
// This is needed to supress the unused variable warning | |
} |
This file contains 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
// MARK: Keyed Callbacks | |
public protocol CallbackHandle | |
{ | |
} | |
private class KeyedCallbackHandle<CallbackParameters> : CallbackHandle, Equatable | |
{ | |
typealias Callback = (CallbackParameters) -> Void | |
let key: String | |
let callback : Callback | |
var onDeinit : (()->Void)? | |
init(key: String, callback: Callback) | |
{ | |
self.key = key | |
self.callback = callback | |
} | |
deinit | |
{ | |
onDeinit?() | |
} | |
} | |
private func ==<T>(lhs: KeyedCallbackHandle<T>, rhs: KeyedCallbackHandle<T>) -> Bool | |
{ | |
return lhs === rhs | |
} | |
private class WeakKeyedCallbackHandle<CallbackParameters> : Equatable | |
{ | |
weak var handle : KeyedCallbackHandle<CallbackParameters>? | |
init(_ handle: KeyedCallbackHandle<CallbackParameters>) | |
{ | |
self.handle = handle | |
} | |
} | |
private func ==<T>(lhs: WeakKeyedCallbackHandle<T>, rhs: WeakKeyedCallbackHandle<T>) -> Bool | |
{ | |
return lhs.handle == rhs.handle | |
} | |
private class KeyedCallbackHandles<CallbackParameters> | |
{ | |
private var keyedHandles = [String: [WeakKeyedCallbackHandle<CallbackParameters>]]() | |
func add(handle: KeyedCallbackHandle<CallbackParameters>) | |
{ | |
handle.onDeinit = { [weak self, weak handle] in | |
if let s = self, let h = handle | |
{ | |
s.remove(h) | |
} | |
} | |
let weakHandle = WeakKeyedCallbackHandle(handle) | |
if var handles = keyedHandles[handle.key] | |
{ | |
handles.append(weakHandle) | |
keyedHandles[handle.key] = handles | |
} | |
else | |
{ | |
keyedHandles[handle.key] = [weakHandle] | |
} | |
} | |
func remove(handle: KeyedCallbackHandle<CallbackParameters>) | |
{ | |
if var handles = keyedHandles[handle.key], | |
let index = handles.indexOf(WeakKeyedCallbackHandle(handle)) | |
{ | |
handles.removeAtIndex(index) | |
if handles.count > 0 | |
{ | |
keyedHandles[handle.key] = handles | |
} | |
else | |
{ | |
keyedHandles.removeValueForKey(handle.key) | |
} | |
} | |
} | |
func handlesForKey(key: String) -> [KeyedCallbackHandle<CallbackParameters>]? | |
{ | |
var handles : [KeyedCallbackHandle<CallbackParameters>]? | |
if let weakHandles = keyedHandles[key] | |
{ | |
handles = weakHandles.flatMap({ $0.handle }) | |
} | |
return handles | |
} | |
} | |
public class KeyedCallbacks<CallbackParameters> | |
{ | |
typealias Callback = (CallbackParameters) -> Void | |
private var keyedHandles = KeyedCallbackHandles<CallbackParameters>() | |
public init() | |
{ | |
} | |
public func register(key: String, callback: Callback) -> CallbackHandle | |
{ | |
let handle = KeyedCallbackHandle<CallbackParameters>(key:key, callback:callback) | |
keyedHandles.add(handle) | |
return handle | |
} | |
public func deregister(handle: CallbackHandle) | |
{ | |
if let keyedCallbackHandle = handle as? KeyedCallbackHandle<CallbackParameters> | |
{ | |
keyedHandles.remove(keyedCallbackHandle) | |
} | |
} | |
public func performCallbacksForKey(key:String, withParameters parameters: CallbackParameters) | |
{ | |
if let handles = keyedHandles.handlesForKey(key) | |
{ | |
for handle in handles | |
{ | |
handle.callback(parameters) | |
} | |
} | |
} | |
} | |
// MARK: Key Value Store | |
protocol KeyValueStore | |
{ | |
func valueForKey(key: String) -> String? | |
func setValue(value: String, forKey key: String) | |
func removeValueForKey(key: String) | |
func registerForUpdates(key: String, callback: (key: String, newValue:String?)->Void) -> CallbackHandle | |
} | |
class DictionaryKeyValueStore : KeyValueStore | |
{ | |
typealias CallbackParameters = (key: String, newValue:String?) | |
typealias UpdatesCallback = CallbackParameters->Void | |
private var store = [String : String]() | |
private var keyedCallbacks = KeyedCallbacks<CallbackParameters>() | |
// MARK: KeyValueStore | |
func valueForKey(key: String) -> String? | |
{ | |
return store[key] | |
} | |
func setValue(value: String, forKey key: String) | |
{ | |
store[key] = value | |
notifyChanges(key, newValue: value) | |
} | |
func removeValueForKey(key: String) | |
{ | |
store.removeValueForKey(key) | |
notifyChanges(key, newValue: nil) | |
} | |
func registerForUpdates(key: String, callback: UpdatesCallback) -> CallbackHandle | |
{ | |
return keyedCallbacks.register(key , callback: callback) | |
} | |
// MARK: Private | |
private func notifyChanges(key: String, newValue: String?) | |
{ | |
keyedCallbacks.performCallbacksForKey(key, withParameters: (key: key, newValue: newValue )) | |
} | |
} | |
public func unused(_ : Any) | |
{ | |
// This is needed to supress the unused variable warning | |
} | |
public func usage() | |
{ | |
let keyValueStore = DictionaryKeyValueStore() | |
let handle1 = keyValueStore.registerForUpdates("a") { print(" ## \($0)") } | |
unused(handle1) | |
do | |
{ | |
let handle2 = keyValueStore.registerForUpdates("a") { print(" >> \($0)") } | |
unused(handle2) | |
keyValueStore.setValue("cool!", forKey: "a") | |
//prints | |
// | |
// ## ("a", Optional("cool!")) | |
// >> ("a", Optional("cool!")) | |
} | |
keyValueStore.setValue("warmer", forKey: "a") | |
//prints | |
// | |
// ## ("a", Optional("warmer")) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
http://www.matrixprojects.net/p/swift-keyed-callbacks