Last active
April 12, 2016 14:28
-
-
Save 53ningen/8c31ffaafbd57086de563e598d5f2706 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 Swift | |
import Foundation | |
let observable = BehaviorSubject(value: "cocoa") | |
let observer = AnyObserver<String> { | |
switch $0 { | |
case .Next(let str): NSLog(str) | |
default: break | |
} | |
} | |
let disposable = observable.subscribe(observer) // observer が observable の購読を開始 | |
observable.on(.Next("chino")) //=> NSLog("chino") | |
observable.on(.Next("maya")) //=> NSLog("maya") | |
observable.on(.Next("megu")) //=> NSLog("megu") | |
disposable.dispose() // 購読を解除 | |
observable.on(.Next("tippy")) //=> もう NSLog されない | |
let obj1 = NSObject() | |
let obj2 = NSObject() | |
unsafeAddressOf(obj1) == unsafeAddressOf(obj1) //=> true | |
unsafeAddressOf(obj1) == unsafeAddressOf(obj2) //=> false | |
extension BehaviorSubject: ObserverType { | |
public typealias E = Element | |
public func on(event: Event<Element>) { | |
switch event { | |
case .Next(let value): | |
self.value = value | |
default: | |
break | |
} | |
observers.forEach { $0.on(event) } | |
} | |
} | |
public final class BehaviorSubject<Element>: Observable<Element> { | |
private var value: Element | |
public init(value: Element) { | |
self.value = value | |
} | |
private var observers = [AnyObserver<Element>]() | |
public override func subscribe<O : ObserverType where O.E == E>(observer: O) -> Disposable { | |
let obs = AnyObserver(observer: observer) | |
observers.append(obs) | |
return SubscriptionDisposable(owner: self, key: unsafeAddressOf(obs)) | |
} | |
func unsubscribe(key: UnsafePointer<Void>) { | |
observers = observers.filter { unsafeAddressOf($0) != key } | |
} | |
} | |
public struct SubscriptionDisposable<T>: Disposable { | |
private weak var owner: BehaviorSubject<T>? | |
private let key: UnsafePointer<Void> | |
public init(owner: BehaviorSubject<T>, key: UnsafePointer<Void>) { | |
self.owner = owner | |
self.key = key | |
} | |
public func dispose() { | |
owner?.unsubscribe(key) | |
} | |
} | |
public class NopDisposable: Disposable { | |
private init() {} | |
public static let instance = NopDisposable() | |
public func dispose() {} | |
} | |
public enum Event<Element> { | |
case Next(Element) | |
case Error(ErrorType) | |
case Completed | |
} | |
extension Event { | |
public var isStopEvent: Bool { | |
switch self { | |
case .Next: return false | |
case .Error, .Completed: return true | |
} | |
} | |
} | |
public protocol ObserverType { | |
associatedtype E | |
// 通知を受ける口 | |
func on(event: Event<E>) | |
} | |
public protocol ObservableType { | |
associatedtype E | |
// 通知先を登録する口 | |
func subscribe<O: ObserverType where O.E == E>(observer: O) -> Disposable | |
} | |
public protocol Disposable { | |
func dispose() | |
} | |
public class AnyObserver<Element>: ObserverType { | |
public typealias E = Element | |
public typealias EventHandler = Event<E> -> Void | |
private let eventHandler: EventHandler | |
public init(eventHandler: EventHandler) { | |
self.eventHandler = eventHandler | |
} | |
public init<O: ObserverType where O.E == Element>(observer: O) { | |
self.eventHandler = observer.on | |
} | |
public func on(event: Event<E>) { | |
eventHandler(event) | |
} | |
} | |
public class Observable<Element>: ObservableType { | |
public typealias E = Element | |
public func subscribe<O : ObserverType where O.E == E>(observer: O) -> Disposable { | |
abstractMethod() | |
} | |
} | |
/// 抽象メソッドを表現するための苦肉の策 | |
@noreturn func abstractMethod() -> Void { | |
fatalError("abstract method") | |
} | |
// String値を状態として持つ、Observable(観測可能な)値 | |
let observable = Variable("cocoa") | |
// Observable<String> に状態遷移に対して、何かアクションを行いたい観測者 | |
let observer = AnyObserver<String>{ | |
// 具体的なアクションをここで定める | |
switch $0 { | |
case .Next(let str): NSLog(str) | |
default: break | |
} | |
} | |
// observer が observable の観測を開始する(観測を終了するためのオブジェクトが返る) | |
let disposable = observable.asObservable().subscribe(observer) | |
// observable に状態遷移を発生させる => NSLog("chino") が実行される | |
observable.value = "chino" | |
disposable.dispose() //=> 観測を終了する | |
observable.value = "tippy" //=> observableの状態遷移時にもうなにも起こらない | |
func setNumber(number: Int) { | |
lock.lock() | |
self.number = number | |
lock.unlock() | |
} | |
func setNumber(number: Int) { | |
lock.lock(); defer { lock.unlock() } | |
self.number = number | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment