2022-03-10

iOS开发:MVP


iOS MVP模式,Github代码在此

上次说到MVVM,这次说MVP
MVVM更多强调View和ViewModel的联系,MVP是把一部分的VC逻辑转移到Presenter
如图(图无VC,同理,并不是说VC省去了,只是没画…)

还是写个TableView,这次带网络请求,所以目标就是把网络请求的代码扔到Presenter里给我们的VC减减肥,
在Presenter里,还是和MVC一样的delegate思想,要求调用的VC遵循这个协议,并且封装了网络请求和其他的业务逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protocol UserPresenterDelegate: AnyObject {
func presentUsers(users: [User])
func presentAlert(title: String, message: String)
}

typealias Presenter = UserPresenterDelegate & UIViewController

class UserPresenter {

weak var delegate: UserPresenterDelegate?

public func setViewDelegate(delegate: Presenter) {
self.delegate = delegate
}

public func getUsers() {
guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { return }

URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
guard let data = data, error == nil else {
return
}
do {
let users = try JSONDecoder().decode([User].self, from: data)
print(users)

self?.delegate?.presentUsers(users: users)
} catch {
print(error)
}
}.resume()
}
}

Model里就是简单的解码json数据

1
2
3
4
struct User: Codable {
let name: String
let email: String
}

在VC里要遵循Presenter的协议,然后通过presenter请求数据,更新tableview,例子很简单,可以看到把网络请求的功能从VC挪走
后续需要扩展业务的话可以在PresenterDelegate里增加,然后在VC里回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class UserVC: UIViewController, UITableViewDelegate, UITableViewDataSource {

let tableView: UITableView = {
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
return tableView
}()

private let presenter = UserPresenter()

private var users: [User] = []

override func viewDidLoad() {
super.viewDidLoad()
title = "Users"

presenter.delegate = self
presenter.getUsers()

view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self


}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.frame = view.bounds
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let user = self.users[indexPath.row]
cell.textLabel?.text = "👾\(user.name) 📧\(user.email)"
return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
users.count
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}

extension UserVC: UserPresenterDelegate {
func presentUsers(users: [User]) {
self.users = users

DispatchQueue.main.async {
self.tableView.reloadData()
}
}

func presentAlert(title: String, message: String) {
//更多的业务
}
}