Skip to content

Instantly share code, notes, and snippets.

@possen
Last active November 9, 2015 04:01
Show Gist options
  • Save possen/41b69f4d4f53e5102620 to your computer and use it in GitHub Desktop.
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
//
// 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