Created
December 27, 2022 20:40
-
-
Save chunkyguy/c91593df9919d47e856944aa98541287 to your computer and use it in GitHub Desktop.
Poor man's State and Binding without 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
@dynamicMemberLookup | |
class Variable<T> { | |
var value: T { | |
get { sub.value } | |
set { sub.value = newValue } | |
} | |
var stream: AnyPublisher<T, Never> { | |
return sub.eraseToAnyPublisher() | |
} | |
subscript<P>(dynamicMember keyPath: WritableKeyPath<T, P>) -> P { | |
get { sub.value[keyPath: keyPath] } | |
set { sub.value[keyPath: keyPath] = newValue } | |
} | |
fileprivate let sub: CurrentValueSubject<T, Never> | |
init(_ sub: CurrentValueSubject<T, Never>) { | |
self.sub = sub | |
} | |
} | |
class State<T>: Variable<T> { | |
var binding: Binding<T> { | |
return Binding(self) | |
} | |
init(_ value: T) { | |
super.init(CurrentValueSubject(value)) | |
} | |
} | |
class Binding<T>: Variable<T> { | |
init(_ state: State<T>) { | |
super.init(state.sub) | |
} | |
} |
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 | |
struct Story { | |
var text: String | |
} | |
class TextEditViewController: UIViewController, UITextViewDelegate { | |
private let story: Binding<Story> | |
init(story: Binding<Story>) { | |
self.story = story | |
super.init(nibName: nil, bundle: nil) | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
let textVw = UITextView(frame: .zero) | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.addSubview(textVw) | |
textVw.text = story.text | |
textVw.delegate = self | |
title = "Story Editor" | |
view.backgroundColor = .white | |
} | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
textVw.frame = view.bounds | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
textVw.becomeFirstResponder() | |
} | |
func textViewDidChange(_ textView: UITextView) { | |
story.text = textView.text | |
} | |
} | |
class RootViewController: UIViewController { | |
let label = UILabel(frame: .zero) | |
let story = State(Story(text: "")) | |
var cancellables = Set<AnyCancellable>() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.addSubview(label) | |
label.backgroundColor = .white | |
label.textAlignment = .center | |
view.backgroundColor = .gray | |
title = "Story Viewer" | |
story.stream.sink { [weak self] nextStory in | |
print("recv: \(nextStory.text)") | |
assert(Thread.isMainThread) | |
self?.label.text = nextStory.text | |
}.store(in: &cancellables) | |
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(onEdit)) | |
} | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
label.frame = CGRect(origin: .zero, size: CGSize(width: view.bounds.width - 40, height: 100)) | |
label.center = view.center | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
label.text = story.value.text | |
} | |
@objc func onEdit() { | |
let textEditVwCtrl = TextEditViewController(story: story.binding) | |
navigationController?.pushViewController(textEditVwCtrl, animated: true) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment