2022-02-25

iOS开发:MVVM


iOS MVVM模式

MVVM如图,是为了解决MVC在大项目里VC变得臃肿的模式

典型的MVC就如写个简单的TableView,逻辑都扔到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
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

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

let data = ["1", "2", "3"]

override func viewDidLoad() {
super.viewDidLoad()
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)
cell.textLabel?.text = data[indexPath.row]
return cell
}

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

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

随着Data的变化,抽取出ViewModel这一概念,使得cell的数据和视图的更新多了一层

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
struct User {
let name: String
let nation: String
}

struct CellViewModel {
let name: String
let nation: String
}

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

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

let data = [
User(name: "haoboxuxu", nation: "China"),
User(name: "Batman", nation: "Gotham"),
User(name: "Hopper X", nation: "Space"),
]

override func viewDidLoad() {
super.viewDidLoad()
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 model = data[indexPath.row]
let viewModel = CellViewModel(name: model.name, nation: model.nation)
cell.textLabel?.text = "\(viewModel.name) \(viewModel.nation)"
return cell
}

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

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

你可能觉得这样和MVC没什么大区别,但是到了如果要自定义cell或者其他自定义视图的场景就更加展现出用途

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
// 自定的UITableViewCell
class CustomCell: UITableViewCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var nationLabel: UILabel!

static let cellID = "CustomCell"

static func nib() -> UINib {
return UINib(nibName: "CustomCell", bundle: nil)
}

override func awakeFromNib() {
super.awakeFromNib()
}

override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}

func configWith(_ vm: CellViewModel) {
nameLabel.text = vm.name
nationLabel.text = vm.nation
}
}

// 在主VC里
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

let tableView: UITableView = {
let tableView = UITableView()
tableView.register(CustomCell.nib(), forCellReuseIdentifier: CustomCell.cellID)
return tableView
}()

// ...

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.cellID, for: indexPath) as! CustomCell
let model = data[indexPath.row]
let viewModel = CellViewModel(name: model.name, nation: model.nation)
cell.configWith(viewModel) //数据交给他
return cell
}
// ...
}

当当!