Last active
August 29, 2015 14:04
-
-
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
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
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