前言
- MVP 全稱:Model-View-Presenter
- MVP架構模式是從MVC演變過來的(很多架構都是的)
- MVP/MVC思想類似,由Presenter/Controller負責業務邏輯
百度百科上已經介紹的非常清楚和細致,關于MVP/MVC的介紹
MVC架構
SwiftMVP Demo地址:
https://github.com/hellolad/Swift-MVP
當你要用Swift開發項目的時候,總是想著找一些好用的東西,讓我們的的項目兼容性更好,效率更高,運行速度更快,當然寫代碼也要更舒服。
抽了一點時間研究了一下MVP,并且用Swift方式實現了一遍,雖然只是一個例子,但是還是感覺到MVP的模型數據分離真的很好。
需要用到的Swift文件:
主要:
- CacheModel.swift
- CachePresenter.swift
- CacheViewController.swift
- CacheProtocol.swift
- Presenter
次要 - HTTPClient.swift
- HTTPResponseProtocol.swift
Presenter.swift
protocol Presenter {
associatedtype T
var view: T? { get set }
mutating func initial(_ view: T)
}
extension CachePresenter: Presenter {}
Presenter協議,定義了一個屬性view, 和一個函數initial。
view的作用最后就是你傳進來的Controller。initial的作用是為了給view賦值,并且初始化一個httpClient,在后面可以看到。
HTTPClient.swift
struct HTTPClient {
// typealias Paramters = Dictionary<String, Any>
var reponseHandle: HTTPResponseProtocol?
init(handle: HTTPResponseProtocol?) {
self.reponseHandle = handle
}
func get(url: String) {
let session = URLSession(configuration: URLSessionConfiguration.default)
let request = URLRequest(url: URL(string: url)!)
session.dataTask(with: request, completionHandler: {
data, response, error in
if error == nil {
if let da = data,
let any = try? JSONSerialization.jsonObject(with: da, options: .mutableContainers),
let dict = any as? [String: Any] {
self.reponseHandle?.onSuccess(object: dict)
}
} else {
self.reponseHandle?.onFailure(error: error!)
}
}).resume()
}
}
HTTPClient設置了一個代理屬性responseHandle,通過init函數給它賦值從而達到在CachePresenter里可以回調到它的兩個函數。get函數就是從服務器獲取數據。
HTTPResponseProtocol.swift
protocol HTTPResponseProtocol {
func onSuccess(object: Dictionary<String, Any>)
func onFailure(error: Error)
}
HTTPResponseProtocol定義了兩個函數需要你去實現,一個是成功一個是失敗。
CacheModel.swift
struct CacheModel {
var origin: String?
var url: String?
init() {
// ?? This is CacheModel
}
static func fromJSON(_ dictionary: [String: Any]?) -> CacheModel? {
if let json = dictionary {
var cm = CacheModel()
cm.origin = json["origin"] as? String
cm.url = json["url"] as? String
return cm
}
return nil
}
}
網絡請求的數據用的是httpbin.org的一個測試請求返回的數據
http://httpbin.org/cache/2000
CacheModel定義了兩個屬性和一個靜態函數。
CacheProtocol.swift
protocol CacheProtocol {
func onGetCacheSuccess(model: CacheModel?)
func onGetCacheFailure(error: Error)
}
CacheProtocol是Controller遵從的協議,只有Controller遵從了這個協議,才能拿到從服務器拿到的CacheModel的值。
CachePresenter.swift (重點)
struct CachePresenter<U> where U: CacheProtocol {
var view: U?
mutating func initial(_ view: U) {
self.view = view
self.httpClient = HTTPClient(handle: self)
}
var httpClient: HTTPClient?
init() {}
typealias Value = Int
func getCache(by integer: Value) {
// 網絡請求 ...
self.httpClient?.get(url: "http://httpbin.org/cache/\(integer)")
}
}
extension CachePresenter: HTTPResponseProtocol {
func onSuccess(object: Dictionary<String, Any>) {
view?.onGetCacheSuccess(model: CacheModel.fromJSON(object))
}
func onFailure(error: Error) {
print(error)
}
}
- CachePresenter類指定了一個泛型U, U指定了必須是實現了CacheProtocol協議的類,我們知道上面我們說到實現CacheProtocol的類是Controller。
- 之后我們實現了Presenter協議的屬性和函數分別給它賦值,上面我們說了在inital函數里初始化了httpClient并且它的responseProtocol是CachePresenter。
- 實現HTTPResponseProtocol協議 onSuccess, onFailure
最后我們的get函數拿到的數據并把數據代理到當前的onSuccess函數,然后我們的Presenter的view是一個CacheProtocol,所以它可以調用onGetCacheSuccess,然后CacheProtocol又是Controller實現的,最后就完成了一個閉環。
CacheViewController.swift
class CacheViewController: UIViewController {
private var cachePresenter = CachePresenter<CacheViewController>()
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nil, bundle: nil)
self.cachePresenter.initial(self)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
reloadData()
}
func reloadData() {
// 請求網絡
self.cachePresenter.getCache(by: 2000)
}
}
extension CacheViewController: CacheProtocol {
// 獲取成功
func onGetCacheSuccess(model: CacheModel?) {
dump(model)
DispatchQueue.main.async {
self.view.backgroundColor = .white
let lab = UILabel()
lab.textColor = .black
lab.textAlignment = .center
lab.text = "\(model?.origin ?? "") \n \(model?.url ?? "")"
lab.numberOfLines = 2
lab.frame = CGRect(x: 0, y: 100, width: UIScreen.main.bounds.width, height: 200)
self.view.addSubview(lab)
}
}
// 獲取失敗
func onGetCacheFailure(error: Error) {
dump(error)
}
}
CacheViewController 初始化cachePresenter,并把自己self交給cachepresenter的initial函數。在reloadData里調用get函數從服務器獲取數據,最后經過CachePresenter拿到代理函數,最后將數據賦值給Label顯示。
最重要的類是CachePresenter它負責獲取數據,并和model,view進行交互。
-- Finished --
參考:
- http://www.lxweimin.com/p/abea207c23e7 OC版本
- https://baike.baidu.com/item/MVP%E6%A8%A1%E5%BC%8F/10961746?fr=aladdin 百度百科
其他:
- 在Swift版本里做了一些優化丟掉了HttpPresenter這個類。
- https://github.com/hellolad/Swift-MVP SwiftMVP Demo地址