Created
January 17, 2019 09:11
-
-
Save timstudt/cf58b5633477acadf0a94516b693f9e8 to your computer and use it in GitHub Desktop.
Revisions
-
timstudt created this gist
Jan 17, 2019 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,140 @@ //: 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()