Created
July 23, 2015 10:14
-
-
Save chrishulbert/5046d21000abadad45e6 to your computer and use it in GitHub Desktop.
Example of a simple Swift alternative to KVO. Inspired by reactive cocoa's MutableProperty. Weakly-referenced subscribers and all.
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 | |
// Simple observable property | |
// Careful: Not thread safe! You should use this only from the main thread, or modify to | |
// have locks. | |
class Property<T> { | |
private var _value: T | |
var value: T { | |
get { return _value } | |
set { | |
_value = newValue | |
tellSubscribers() | |
} | |
} | |
init(_ value: T) { | |
_value = value | |
} | |
var subscriptions = [Subscription<T>]() | |
func subscribe(subscriber: AnyObject, next: T -> Void) { | |
subscriptions.append(Subscription(subscriber: subscriber, next: next)) | |
next | |
} | |
private func tellSubscribers() { | |
subscriptions = subscriptions.flatMap(tellAndFilterSubscription) | |
} | |
private func tellAndFilterSubscription(subscription: Subscription<T>) -> Subscription<T>? { | |
if subscription.subscriber != nil { // Subscriber is still around. | |
subscription.next(_value) | |
return subscription | |
} else { // Subscriber has gone, so cull this subscription. | |
return nil | |
} | |
} | |
} | |
struct Subscription<T> { | |
weak var subscriber: AnyObject? | |
let next: T -> Void | |
} | |
// Tests / examples of how to use it. | |
class Foo { // The one with the property. | |
let property = Property("Blah") // Here's how you declare a property. | |
} | |
class Bar { // The observer. | |
var string: String? | |
} | |
class Test { | |
var string: String? | |
func test() { | |
// Setup bar subscribed to foo's property. | |
let foo = Foo() | |
var bar: Bar? = Bar() | |
foo.property.subscribe(bar!) { | |
[weak bar] newValue in | |
bar?.string = newValue | |
} | |
// Example of how to subscribe. | |
foo.property.subscribe(self) { | |
[weak self] newValue in | |
self?.string = newValue | |
} | |
// Test it calls the subscriber. | |
foo.property.value = "Test" | |
print(bar!.string) // Should be "Test" | |
print(string) // Should also be "Test" | |
// Test it culls nilled subscribers. | |
print(foo.property.subscriptions.count) // Should be 1. | |
bar = nil | |
foo.property.value = "GiveItAChanceToCull" | |
print(foo.property.subscriptions.count) // Should be 0. | |
} | |
} | |
Test().test() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment