Skip to content

Instantly share code, notes, and snippets.

@andreyvit
Last active August 29, 2015 14:04
Show Gist options
  • Save andreyvit/1aa998e6a8e9541cf24b to your computer and use it in GitHub Desktop.
Save andreyvit/1aa998e6a8e9541cf24b to your computer and use it in GitHub Desktop.
Code from “In search of a clean closure-based observation API in Swift” on Apple Dev Forums
import Foundation
func weakify<T: AnyObject>(object: T, block: (T) -> Void) -> () -> Void {
weak var weakObject = object
return {
if let strongObject = weakObject {
block(strongObject)
}
}
}
class ObservationProxy {
public let name: String
weak var observation: Observation?
init(name: String, observation: Observation) {
println("ObservationProxy.init(\(name))")
self.name = name
self.observation = observation
observations.append(self)
}
func indexOfSelf() -> Int? {
for index in 0 ..< observations.count {
if observations[index] === self {
return index
}
}
return nil
}
func trigger() {
observation?.trigger()
}
func remove() {
println("ObservationProxy.remove(\(name))")
if let index = indexOfSelf() {
observations.removeAtIndex(index)
}
}
}
class Observation {
public let name: String
public let block: () -> Void
var proxy: ObservationProxy!
public init(name: String, block: () -> Void) {
println("Observation.init(\(name))")
self.name = name
self.block = block
proxy = ObservationProxy(name: name, observation: self)
}
func trigger() {
block()
}
deinit {
println("Observation.deinit(\(name))")
proxy.remove()
}
}
var observations = [ObservationProxy]()
func sendNotification(name: String) {
println("sendNotification \(name), observations.count = \(observations.count)")
for observation in observations {
if observation.name == name {
observation.trigger()
}
}
}
func addNotificationObserver(name: String, block: () -> Void) -> Observation {
return Observation(name: name, block)
}
func addNotificationObserver(name: String, object: NSObject, selector: Selector) {
}
func removeNotificationObservers(object: NSObject) {
}
class Foo1 {
init() {
addNotificationObserver("SomethingDidChange") { self.doSomethingCool() }
addNotificationObserver("SomethingElseDidChange") { self.doSomethingCool() }
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
}
class Foo2 {
init() {
addNotificationObserver("SomethingDidChange") { [weak self] in self?.doSomethingCool(); return }
addNotificationObserver("SomethingElseDidChange") { [weak self] in self?.doSomethingCool(); return }
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
}
class Foo3 {
init() {
addNotificationObserver("SomethingDidChange", doSomethingCool)
addNotificationObserver("SomethingElseDidChange", doSomethingCool)
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
}
class Foo4 {
private let observation1, observation2: Observation!
init() {
observation1 = addNotificationObserver("SomethingDidChange", doSomethingCool)
observation2 = addNotificationObserver("SomethingElseDidChange", doSomethingCool)
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
}
class Badass {
init() {
println("Badass.init")
}
deinit {
println("Badass.deinit")
sendNotification("SomethingElseDidChange")
}
}
class Foo5 {
private let badass = Badass()
private var observation1, observation2: Observation!
init() {
println("Foo.init")
observation1 = addNotificationObserver("SomethingDidChange") { [weak self] in self?.doSomethingCool(); if !self { println("Foo5 is nil, skipping SomethingDidChange") }; return }
observation2 = addNotificationObserver("SomethingElseDidChange") { [weak self] in self?.doSomethingCool(); if !self { println("Foo5 is nil, skipping SomethingElseDidChange")}; return }
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
deinit {
println("Foo.deinit BEGIN")
sendNotification("SomethingDidChange")
println("Foo.deinit END")
}
}
class Foo6 {
private var observations = [Observation]()
init() {
println("Foo.init")
observations.append(addNotificationObserver("SomethingDidChange") { [weak self] in self?.doSomethingCool(); return })
observations.append(addNotificationObserver("SomethingElseDidChange") { [weak self] in self?.doSomethingCool(); return })
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
}
var yourFavoriteMagic: [Observation] = []
extension NSObject {
private var observations: [Observation] {
get { return yourFavoriteMagic }
set { yourFavoriteMagic = newValue }
}
func on7(name: String, block: () -> Void) {
observations.append(addNotificationObserver(name, block))
}
}
class Foo7: NSObject {
init() {
super.init()
println("Foo.init")
on7("SomethingDidChange") { [weak self] in self?.doSomethingCool(); return }
on7("SomethingElseDidChange") { [weak self] in self?.doSomethingCool(); return }
yourFavoriteMagic = [] // simulate cleanup of associated value
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
}
class Foo8: NSObject {
init() {
super.init()
println("Foo.init")
addNotificationObserver("SomethingDidChange", self, "doSomethingCool")
addNotificationObserver("SomethingElseDidChange", self, "doSomethingCool")
}
deinit {
removeNotificationObservers(self) // can be replaced by dealloc swizzling in addNotificationObserver
yourFavoriteMagic = [] // simulate cleanup of associated value
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
}
func addNotificationObserver<T: NSObject>(object: T, name: String, block: (T) -> Void) {
object.observations.append(addNotificationObserver(name, weakify(object, block)))
}
class Foo9: NSObject {
init() {
super.init()
println("Foo9.init")
addNotificationObserver(self, "SomethingDidChange") { $0.doSomethingCool() }
addNotificationObserver(self, "SomethingElseDidChange") { $0.doSomethingCool() }
}
func doSomethingCool() {
println("Pretty cool, huh?")
yourFavoriteMagic = [] // simulate cleanup of associated value
}
}
func on<T: NSObject>(name: String, object: T, block: (T) -> () -> Void) {
weak var weakObject: T? = object
object.observations.append(Observation(name: name, {
if let obj = weakObject {
block(obj)()
}
}))
}
class Foo10: NSObject {
init() {
super.init()
println("Foo10.init")
on("SomethingDidChange", self, Foo10.doSomethingCool)
on("SomethingElseDidChange", self, Foo10.doSomethingCool)
}
deinit {
removeNotificationObservers(self) // can be replaced by dealloc swizzling in addNotificationObserver
yourFavoriteMagic = [] // simulate cleanup of associated value
}
func doSomethingCool() {
println("Pretty cool, huh?")
}
}
class Bar10: Foo10 {
override func doSomethingCool() {
super.doSomethingCool()
println("One more thing.")
}
}
var foo9: Foo9? = Foo9(); 42
sendNotification("SomethingDidChange")
foo9 = nil
sendNotification("SomethingDidChange")
var foo10: Foo10? = Bar10(); 42
sendNotification("SomethingDidChange")
foo10 = nil
sendNotification("SomethingDidChange")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment