Last active
November 9, 2015 04:01
-
-
Save possen/41b69f4d4f53e5102620 to your computer and use it in GitHub Desktop.
Example Implementation of a closure based api similar to NSNotificationCenter -- should support multiple threads by serializing access, allows adding observers for a particular key where all blocks will get called back. for that 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
// | |
// Description: Example implementation similar to NSNotificationCenter | |
// Language: Swift 2.1 | |
// Date: November 7, 2015 | |
// | |
// Author: Paul Ossenbruggen | |
// | |
// should support multiple threads by serializing access. | |
// | |
// allows posting to observers for a particular key where all blocks will get | |
// called back for that key | |
// | |
import Foundation | |
typealias Observer = (key : String, data : AnyObject) -> Void | |
struct Notification : Hashable, Equatable { | |
let key : String | |
let closure : Observer | |
private let id : Int | |
var hashValue : Int { | |
return id.hashValue ^ key.hashValue | |
} | |
} | |
func ==(lhs : Notification, rhs : Notification) -> Bool { | |
return lhs.key == rhs.key && lhs.id == rhs.id | |
} | |
class NotificationCenter { | |
private var dict : [String : Set<Notification>] = [:] | |
private var id = 0 | |
private let queue = dispatch_queue_create("notificationCeneterQueue", DISPATCH_QUEUE_SERIAL) | |
func addObserverForKey(key : String, closure : Observer) -> Notification? { | |
var notification : Notification? = nil | |
dispatch_sync(queue) { [unowned self] in | |
var set = self.dict[key] | |
if set == nil { | |
set = Set<Notification>() | |
} | |
let note = Notification(key: key, closure: closure, id: ++self.id) | |
set!.insert(note) | |
notification = note | |
self.dict[key] = set | |
} | |
return notification | |
} | |
func removeObserverForNotification(notification : Notification) { | |
dispatch_sync(queue) { [unowned self] in | |
let key = notification.key | |
let set = self.dict[key] | |
if var set = set { | |
set.remove(notification) | |
self.dict[key] = set.isEmpty ? nil : set | |
} | |
} | |
} | |
func removeAllObserversForKey(key : String) { | |
dispatch_sync(queue) { [unowned self] in | |
self.dict[key] = nil | |
} | |
} | |
func postNoticationForKey(key : String, data : AnyObject!) { | |
dispatch_sync(queue) { [unowned self] in | |
let set = self.dict[key] | |
if let set = set { | |
for notification in set { | |
notification.closure(key: key, data: data) | |
} | |
} | |
} | |
} | |
} | |
// Tests. try in playground | |
print("begin") | |
// does not use a singleton, they are essentially globals, | |
// this allows multiple notification centers | |
let nc = NotificationCenter() | |
// add a notification observer | |
let notification0 = nc.addObserverForKey("abc") { name, data in | |
print(" notification \(name) \(data)") | |
} | |
// add a second notification observer | |
let notification1 = nc.addObserverForKey("cde") { (name, data) -> Void in | |
print(" notification \(name), \(data)") | |
} | |
// add another that is triggered off the same key as previous | |
let notification2 = nc.addObserverForKey("cde") { (name, data) -> Void in | |
print(" notification \(name), \(data)") | |
} | |
print("post to different keys") | |
nc.postNoticationForKey("abc", data: "mydata") | |
nc.postNoticationForKey("cde", data: "otherdata") | |
nc.postNoticationForKey("cde", data: "foo") | |
print("remove observer 1") | |
nc.removeObserverForNotification(notification1!) | |
nc.postNoticationForKey("abc", data: "mydata") | |
nc.postNoticationForKey("cde", data: "otherdata") | |
nc.postNoticationForKey("cde", data: "foo") | |
print("remove observer 2") | |
nc.removeObserverForNotification(notification2!) | |
nc.postNoticationForKey("abc", data: "mydata") | |
nc.postNoticationForKey("cde", data: "otherdata") | |
nc.postNoticationForKey("cde", data: "foo") | |
print("remove observer 3") | |
nc.removeObserverForNotification(notification0!) | |
nc.postNoticationForKey("abc", data: "mydata") | |
nc.postNoticationForKey("cde", data: "otherdata") | |
nc.postNoticationForKey("cde", data: "foo") | |
print("add a notification observers again") | |
// add a notification observer | |
let notification3 = nc.addObserverForKey("abc") { name, data in | |
print(" notification \(name) \(data)") | |
} | |
// add a second notification observer | |
let notification4 = nc.addObserverForKey("cde") { (name, data) -> Void in | |
print(" notification \(name), \(data)") | |
} | |
// add another that is triggered off the same key as previous | |
let notification5 = nc.addObserverForKey("cde") { (name, data) -> Void in | |
print(" notification \(name), \(data)") | |
} | |
print("post to all") | |
nc.postNoticationForKey("abc", data: "mydata") | |
nc.postNoticationForKey("cde", data: "otherdata") | |
nc.postNoticationForKey("cde", data: "foo") | |
print("remove all observers for key") | |
nc.removeAllObserversForKey("cde") | |
print("post to all, should still print abc since we did not remove that one") | |
nc.postNoticationForKey("abc", data: "mydata") | |
nc.postNoticationForKey("cde", data: "otherdata") | |
nc.postNoticationForKey("cde", data: "foo") | |
print("finished") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment