在談架構(gòu)之前讶迁,其實(shí)蘋果是建議我們開啟用戶的
1. MVC
這個(gè)比較簡單
預(yù)期:
現(xiàn)實(shí):
view 和 model 還是 沒有解耦肴捉;
- view事件 (比如點(diǎn)擊 + )
- 響應(yīng)view的事件(data頁面顯示數(shù)字+1)
- 業(yè)務(wù)邏輯领跛,網(wǎng)絡(luò)請求 =》 影響UI 也有不影響UI的
- 影響UI就需要抽離出來
2. MVP
V: View + controller;
P: View的 一個(gè) 處理 和 響應(yīng)的 管理者乏德,所以XCTest的時(shí)候就不需要View的邏輯,可以通過Present來模擬吠昭;
交互: V會(huì)持有P喊括, P 持有V的弱引用
import UIKit
// MVP
// data
struct Person { // Model
let firstName: String
let lastName: String
}
// view 的協(xié)議
protocol GreetingView : AnyObject {
func setGreeting(greeting: String)
}
// present 持有view的協(xié)議
protocol GreetingViewPresenter {
init(view: GreetingView, person: Person)
func showGreeting()
}
// 實(shí)例化prsent
class GreetingPresenter: GreetingViewPresenter {
// P 弱持有 V
weak var view: GreetingView!
let person: Person
required init(view: GreetingView, person: Person) {
self.view = view
self.person = person
}
func showGreeting() {
// 處理邏輯事件
let greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
// 處理好了回傳給view
self.view.setGreeting(greeting: greeting)
}
}
// VC實(shí)現(xiàn) Present的協(xié)議
class MVPGreetingViewController: UIViewController, GreetingView {
// V 持有 P
var presenter: GreetingViewPresenter!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
self.setupUI()
self.showGreetingButton.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)
}
func setGreeting(greeting: String) {
self.greetingLabel.text = greeting
}
@objc func didTapButton(_ btn: UIButton) -> Void {
self.presenter.showGreeting()
}
// layout code go here
func setupUI() {
self.view.addSubview(self.showGreetingButton)
self.view.addSubview(self.greetingLabel)
self.showGreetingButton.frame = CGRect.init(x: 10, y: 100, width: 100, height: 50);
self.showGreetingButton.backgroundColor = UIColor.blue
self.greetingLabel.frame = CGRect.init(x: 20, y: 250, width: 200, height: 60);
self.greetingLabel.backgroundColor = UIColor.gray
}
}
調(diào)用過程:
let model = Person(firstName: "David", lastName: "Blaine")
let vc = MVPGreetingViewController()
let presenter = GreetingPresenter(view: vc, person: model)
vc.presenter = presenter
self.navigationController?.pushViewController(vc, animated: true)
3. VIPER
V: View + Controller
I: Interactor (邏輯業(yè)務(wù)處理者)
P: Present
E: model
R: 路由
暫時(shí)不考慮路由,我們可以看到 和 MVP 相比怎诫,多了一個(gè) Interactor瘾晃,其實(shí)就是 防止Present 過于龐大贷痪,而把以前在Present 處理的業(yè)務(wù)邏輯 細(xì)分到 不同的 Interactor 里面幻妓;
import UIKit
struct Person2 { // 實(shí)體 Model
let firstName: String
let lastName: String
}
struct GreetingData { // 傳遞數(shù)據(jù)結(jié)構(gòu)(不是實(shí)體)
let greeting: String
let subject: String
}
/**
Interactor
*/
protocol GreetingProvider {
func provideGreetingData()
}
class GreetingInteractor: GreetingProvider {
weak var output: GreetingOutput!
func provideGreetingData() {
let person = Person2(firstName: "David", lastName: "Blaine")// 通常來自于數(shù)據(jù)訪問層
let subject = person.firstName + " " + person.lastName
let greeting = GreetingData(greeting: "Hello", subject: subject)
self.output.receiveGreetingData(greetingData:greeting)
}
}
protocol GreetingView2EventHandler {
func didTapShowGreetingButton()
}
protocol GreetingOutput: AnyObject {
func receiveGreetingData(greetingData: GreetingData)
}
/**
present 還是直接和V 交互,只是抽離了 業(yè)務(wù)邏輯
分類出
【UI點(diǎn)擊 的 業(yè)務(wù)邏輯】
【更新UI的業(yè)務(wù)】
*/
class GreetingPresenter2: GreetingView2EventHandler, GreetingOutput {
weak var view: GreetingView2!
// P 只有 Interactor , 在V 中就可以 拿著 Interactor 去調(diào)用業(yè)務(wù)
var greetingProvider: GreetingProvider!
// UI 點(diǎn)擊 =》 業(yè)務(wù)邏輯(抽離出 Interactor)
func didTapShowGreetingButton() {
// Interactor(解析數(shù)據(jù)) => output (更新UI)
self.greetingProvider.provideGreetingData()
}
//UI 更新 劫拢,上面的 Interactor 處理完了 =》 更新 UI (更新present)
func receiveGreetingData(greetingData: GreetingData) {
let greeting = greetingData.greeting + " " + greetingData.subject
self.view.setGreeting(greeting: greeting)
}
}
// V 暴露給外部的回調(diào)事件肉津;
protocol GreetingView2: AnyObject {
func setGreeting(greeting: String)
}
class VIPERGreetingViewController: UIViewController, GreetingView2 {
var eventHandler: GreetingView2EventHandler!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)
}
@objc func didTapButton(_ button: UIButton) {
// 通過Interactor 去觸發(fā)業(yè)務(wù)邏輯
// 和MVP 使用就不用直接使用P 去觸發(fā)邏輯
self.eventHandler.didTapShowGreetingButton()
}
func setGreeting(greeting: String) {
self.greetingLabel.text = greeting
}
// layout code go here
func setupUI() {
self.view.addSubview(self.showGreetingButton)
self.view.addSubview(self.greetingLabel)
self.showGreetingButton.frame = CGRect.init(x: 10, y: 100, width: 100, height: 50);
self.showGreetingButton.backgroundColor = UIColor.blue
self.greetingLabel.frame = CGRect.init(x: 20, y: 250, width: 200, height: 60);
self.greetingLabel.backgroundColor = UIColor.gray
}
}
外界調(diào)用:
let vc = VIPERGreetingViewController()
let presenter = GreetingPresenter2()
let interactor = GreetingInteractor()
interactor.output = presenter //weak , 需要回調(diào) 業(yè)務(wù)邏輯 給P
presenter.greetingProvider = interactor
presenter.view = vc;
vc.eventHandler = presenter
self.navigationController?.pushViewController(vc, animated: true)
4. MVVM
和 MVP 很相似;
但是不一樣的是舱沧,viewModel 想達(dá)到 model的改變 => View ; View 的改變馬上影響model妹沙,并且 view 和 model 不耦合在一起;
所以就有個(gè) bind的概念熟吏;
類似vue 或者小程序 里面一樣的距糖;
- view 點(diǎn)擊事件 (比如 讓viewModel 當(dāng)做target) =》 事件就傳給了 viewModel =》 viewModel,greeting = "xxxx" 去更改 數(shù)據(jù)
||
V - viewModel.greeting (屬性改變) =》 觸發(fā) view的改變 (UI 展示);