Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //: A UIKit based Playground for presenting user interface
- import UIKit
- import PlaygroundSupport
- // Models
- struct MyViewModel: Equatable { let text: String }
- enum MyError: Error, Equatable {
- case noConnection(String)
- }
- // Protocols
- protocol ViewState: Equatable {
- associatedtype T: Equatable
- associatedtype Error: Equatable
- var isLoading: Bool { get }
- var data: T? { get }
- var error: Error? { get }
- }
- protocol Presenting {
- func loadData()
- }
- protocol UI: class {
- associatedtype State
- func render(state: State)
- }
- // Base Classes
- class Presenter<V: UI> {
- weak var ui: V?
- }
- // Module Classes
- final class MyPresenter: Presenter<MyView>, Presenting {
- func loadData() {
- ui?.render(state: .loading)
- DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
- self.ui?.render(state: .error(.noConnection("oops, we messed up!")))
- }
- DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
- self.ui?.render(state: .loaded(.init(text: "kidding..got some data")))
- }
- }
- }
- class MyView : UIViewController {
- let presenter: MyPresenter
- var lable: UILabel!
- init(presenter: MyPresenter = MyPresenter()) {
- self.presenter = presenter
- super.init(nibName: nil, bundle: nil)
- presenter.ui = self
- }
- required init?(coder aDecoder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- override func loadView() {
- let view = UIView()
- view.backgroundColor = .white
- let label = UILabel()
- label.frame = CGRect(x: 150, y: 200, width: 250, height: 20)
- label.text = "Hello World!"
- label.textColor = .black
- view.addSubview(label)
- self.lable = label
- self.view = view
- }
- override func viewDidAppear(_ animated: Bool) {
- super.viewDidAppear(animated)
- presenter.loadData()
- }
- private func showSpinner() {
- lable.textColor = .gray
- lable.text = "..loading"
- }
- private func show(data: MyViewModel) {
- lable.textColor = .black
- lable.text = data.text
- }
- private func show(error: MyError) {
- lable.textColor = .red
- switch error {
- case .noConnection(let mesg):
- lable.text = mesg
- }
- }
- }
- extension MyView: UI {
- typealias T = State
- func render(state: State) {
- switch state {
- case .loading: showSpinner()
- case .loaded(let data): show(data: data)
- case .error(let error): show(error: error)
- }
- }
- }
- extension MyView {
- enum State {
- typealias T = MyViewModel
- typealias Error = MyError
- case loading, loaded(T), error(Error)
- }
- }
- extension MyView.State: ViewState {
- var isLoading: Bool { return self == .loading }
- var data: MyViewModel? {
- switch self {
- case .loading, .error: return nil
- case .loaded(let data): return data
- }
- }
- var error: MyError? {
- switch self {
- case .loading, .loaded: return nil
- case .error(let mesg): return mesg
- }
- }
- }
- // Present the view controller in the Live View window
- PlaygroundPage.current.liveView = MyView()
Add Comment
Please, Sign In to add comment