Last active
November 24, 2020 08:58
-
-
Save bartleby/11e91ea2158005078ee1f65062e804be to your computer and use it in GitHub Desktop.
Published like SwiftUI
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
// | |
// 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