Skip to content

Instantly share code, notes, and snippets.

@bartleby
Last active November 24, 2020 08:58
Show Gist options
  • Save bartleby/11e91ea2158005078ee1f65062e804be to your computer and use it in GitHub Desktop.
Save bartleby/11e91ea2158005078ee1f65062e804be to your computer and use it in GitHub Desktop.
Published like SwiftUI
//
// ViewController.swift
// Teeeeee
//
// Created by Bartleby Cartman on 23.11.2020.
//
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var textField: UITextField!
@IBOutlet var textLabel: UILabel!
@Published var stringValue: String = ""
override func viewDidLoad() {
super.viewDidLoad()
textLabel << $stringValue
// Do any additional setup after loading the view.
}
func textFieldDidChangeSelection(_ textField: UITextField) {
stringValue = textField.text ?? ""
}
}
// MARK: - Property Wrapper
@propertyWrapper
struct Published<Value> {
var wrappedValue: Value {
get { subject.value }
set { subject.value = newValue }
}
private let subject: CurrentValueSubject<Value, Never>
var projectedValue: CurrentValueSubject<Value, Never> { subject }
init(wrappedValue: Value) {
self.subject = CurrentValueSubject(wrappedValue)
}
}
// MARK: - Subject
final class CurrentValueSubject<Output, Failure: Error> {
typealias Reciver = (Output) -> Bool
var recivers: [Reciver] = []
private let lock = NSRecursiveLock()
private var currentValue: Output
var value: Output {
set {
lock.lock()
sendValueAndConsumeLock(newValue)
}
get {
return currentValue
}
}
init(_ value: Output) {
self.currentValue = value
}
func sink(_ context: AnyObject, receiveValue: @escaping (Output) -> Void) {
lock.lock()
defer { lock.unlock() }
self.recivers.append({ [weak context] v in
guard context != nil else { return false }
receiveValue(v)
return true
})
}
private func sendValueAndConsumeLock(_ newValue: Output) {
defer { lock.unlock() }
currentValue = newValue
self.recivers = self.recivers.filter { $0(newValue) }
}
}
// MARK: - UILabel extension
extension UILabel: Bindable {
func bind<V>(_ b: CurrentValueSubject<V, Never>) {
b.sink(self) { (value) in
self.text = String(describing: value)
}
}
}
// MARK: - Bindable Protocol
protocol Bindable {
func bind<V>(_ b: CurrentValueSubject<V, Never>)
}
// MARK: - Custom Operator
infix operator <<
func <<<T, V>(lhs: T, rhs: CurrentValueSubject<V, Never>) where T: Bindable {
lhs.bind(rhs)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment