Last active
May 13, 2018 00:26
-
-
Save fromkk/2cd5822364a39293be8b48b475f3c8e3 to your computer and use it in GitHub Desktop.
Bind feature with Swift from scratch
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 UIKit | |
public class Variable<T: Equatable> { | |
public var value: T { | |
didSet { | |
obserbers.forEach { | |
$0(value) | |
} | |
} | |
} | |
public init(_ value: T) { | |
self.value = value | |
} | |
public func update(_ value: T) { | |
self.value = value | |
} | |
public typealias Observer = (T) -> () | |
var obserbers: [Observer] = [] | |
public func observe(_ observer: @escaping Observer) { | |
obserbers.append(observer) | |
} | |
} | |
public class UIControlObserver <T: UIControl & Bindable>: NSObject { | |
deinit { | |
subscribers.forEach { (subscriber) in | |
value.removeTarget(self, action: #selector(handle(control:)), for: subscriber.events) | |
} | |
} | |
public let value: T | |
public init(_ value: T) { | |
self.value = value | |
super.init() | |
} | |
public typealias Subscriber = (events: UIControlEvents, handler: (T) -> ()) | |
var subscribers: [Subscriber] = [] | |
public func observe(for events: UIControlEvents, and handler: @escaping (T) -> ()) { | |
value.addTarget(self, action: #selector(handle(control:)), for: events) | |
subscribers.append((events, handler)) | |
value.sendActions(for: events) | |
} | |
public func bind(to variable: Variable<T.BindingType>, events: UIControlEvents = .allEditingEvents) { | |
self.observe(for: events) { [weak variable] (value) in | |
variable?.update(value.observingValue()) | |
} | |
} | |
@objc private func handle(control: UIControl) { | |
subscribers.forEach { (subscriber) in | |
subscriber.handler(value) | |
} | |
} | |
} | |
public protocol Bindable: NSObjectProtocol { | |
associatedtype BindingType: Equatable | |
func observingValue() -> BindingType | |
func updateValue(with value: BindingType) | |
} | |
extension UITextField : Bindable { | |
public typealias BindingType = String | |
public func observingValue() -> String { | |
return self.text ?? "" | |
} | |
public func updateValue(with value: String) { | |
self.text = value | |
} | |
} | |
extension UITextView : Bindable { | |
public typealias BindingType = String | |
public func observingValue() -> String { | |
return self.text | |
} | |
public func updateValue(with value: String) { | |
self.text = value | |
} | |
} | |
extension UISwitch : Bindable { | |
public typealias BindingType = Bool | |
public func observingValue() -> Bool { | |
return self.isOn | |
} | |
public func updateValue(with value: Bool) { | |
self.isOn = value | |
} | |
} | |
extension UISlider : Bindable { | |
public typealias BindingType = Float | |
public func observingValue() -> Float { | |
return self.value | |
} | |
public func updateValue(with value: Float) { | |
self.value = value | |
} | |
} | |
extension UIStepper : Bindable { | |
public typealias BindingType = Double | |
public func observingValue() -> Double { | |
return self.value | |
} | |
public func updateValue(with value: Double) { | |
self.value = value | |
} | |
} | |
let textField = UIControlObserver<UITextField>(UITextField()) | |
let text = Variable<String>("") | |
textField.bind(to: text) | |
textField.value.text = "hello" | |
textField.value.sendActions(for: .editingChanged) | |
textField.value.text = "world" | |
textField.value.sendActions(for: .editingChanged) | |
text.value |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment