Skip to content

Instantly share code, notes, and snippets.

@fromkk
Last active May 13, 2018 00:26
Show Gist options
  • Save fromkk/2cd5822364a39293be8b48b475f3c8e3 to your computer and use it in GitHub Desktop.
Save fromkk/2cd5822364a39293be8b48b475f3c8e3 to your computer and use it in GitHub Desktop.
Bind feature with Swift from scratch
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