Created
February 18, 2020 07:33
-
-
Save zhouhao27/86d46b59a077535fdb763c559ca79b2d to your computer and use it in GitHub Desktop.
A MVP demo
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 characters
//: A UIKit based Playground for presenting user interface | |
import UIKit | |
import PlaygroundSupport | |
struct User { | |
let firstName: String | |
let lastName: String | |
let email: String | |
let age: Int | |
} | |
class UserService { | |
//the service delivers mocked data with a delay | |
func getUsers(callBack:@escaping ([User]) -> Void) { | |
let users = [User(firstName: "Iyad", lastName: "Agha", email: "[email protected]", age: 36), | |
User(firstName: "Mila", lastName: "Haward", email: "[email protected]", age: 24), | |
User(firstName: "Mark", lastName: "Astun", email: "[email protected]", age: 39) | |
] | |
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) { | |
callBack(users) | |
} | |
} | |
} | |
// data passed to view because view doesn't need to know the model itself | |
struct UserViewData { | |
let name: String | |
let age: String | |
} | |
protocol UserView: class { | |
func startLoading() | |
func finishLoading() | |
func setUsers(users: [UserViewData]) | |
} | |
class UserPresenter { | |
private let userService:UserService | |
weak private var userView : UserView? | |
init(userService:UserService){ | |
self.userService = userService | |
} | |
func attachView(view:UserView){ | |
userView = view | |
} | |
func detachView() { | |
userView = nil | |
} | |
func getUsers(){ | |
print("getUsers") | |
self.userView?.startLoading() | |
userService.getUsers{ [weak self] users in | |
self?.userView?.finishLoading() | |
if(users.count == 0){ | |
self?.userView?.setUsers(users:[]) | |
}else{ | |
let mappedUsers = users.map { | |
return UserViewData(name: "\($0.firstName) \($0.lastName)", age: "\($0.age) years") | |
} | |
self?.userView?.setUsers(users: mappedUsers) | |
} | |
} | |
} | |
} | |
class MyViewController : UIViewController { | |
var emptyView: UIView? | |
var tableView: UITableView? | |
var activityIndicator: UIActivityIndicatorView? // TODO: To be implemented | |
private weak var userPresenter: UserPresenter! | |
private var usersToDisplay = [UserViewData]() // covert from model to ViewModel | |
init(presenter: UserPresenter) { | |
super.init(nibName: nil, bundle: nil) | |
self.userPresenter = presenter | |
self.userPresenter.attachView(view: self) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func loadView() { | |
print("loadView") | |
view = UIView() | |
view.backgroundColor = UIColor.white | |
setupEmptyView() | |
setupTableView() | |
} | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
print("viewDidLoad") | |
setupIndicator() | |
self.userPresenter.getUsers() | |
} | |
private func setupEmptyView() { | |
emptyView = UIView() | |
emptyView!.backgroundColor = .yellow | |
view.addSubview(emptyView!) | |
setupConstraints(for: emptyView!) | |
} | |
private func setupTableView() { | |
tableView = UITableView() | |
view.addSubview(tableView!) | |
setupConstraints(for: tableView!) | |
tableView?.delegate = self | |
tableView?.dataSource = self | |
tableView?.register(UITableViewCell.self, forCellReuseIdentifier: "UserCell") | |
} | |
private func setupIndicator() { | |
activityIndicator = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.gray) | |
activityIndicator!.hidesWhenStopped = true | |
view.addSubview(activityIndicator!) | |
activityIndicator!.translatesAutoresizingMaskIntoConstraints = false | |
NSLayoutConstraint.activate([ | |
activityIndicator!.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), | |
activityIndicator!.centerYAnchor.constraint(equalTo: self.view.centerYAnchor) | |
]) | |
} | |
private func setupConstraints(for view: UIView) { | |
view.translatesAutoresizingMaskIntoConstraints = false | |
NSLayoutConstraint.activate([ | |
view.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0), | |
view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0), | |
view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0), | |
view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0), | |
]) | |
} | |
} | |
extension MyViewController: UserView { | |
func startLoading() { | |
activityIndicator?.startAnimating() | |
} | |
func finishLoading() { | |
activityIndicator?.stopAnimating() | |
} | |
func setUsers(users: [UserViewData]) { | |
if users.isEmpty { | |
self.emptyView?.isHidden = false | |
self.tableView?.isHidden = true | |
} else { | |
self.emptyView?.isHidden = true | |
self.tableView?.isHidden = false | |
usersToDisplay = users | |
tableView?.reloadData() | |
} | |
} | |
} | |
extension MyViewController: UITableViewDataSource, UITableViewDelegate { | |
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
return usersToDisplay.count | |
} | |
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "UserCell") | |
let userViewData = usersToDisplay[indexPath.row] | |
cell.textLabel?.text = userViewData.name | |
cell.detailTextLabel?.text = userViewData.age | |
cell.textLabel | |
return cell | |
} | |
} | |
// Present the view controller in the Live View window | |
let presenter = UserPresenter(userService: UserService()) | |
let vc = MyViewController(presenter: presenter) | |
PlaygroundPage.current.liveView = vc | |
//PlaygroundPage.current.needsIndefiniteExecution = true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment