前言
- MVP 全稱:Model-View-Presenter
- MVP架構(gòu)模式是從MVC演變過(guò)來(lái)的(很多架構(gòu)都是的)
- MVP/MVC思想類似仙逻,由Presenter/Controller負(fù)責(zé)業(yè)務(wù)邏輯
百度百科上已經(jīng)介紹的非常清楚和細(xì)致蘸拔,關(guān)于MVP/MVC的介紹
SwiftMVP Demo地址:
https://github.com/hellolad/Swift-MVP
當(dāng)你要用Swift開(kāi)發(fā)項(xiàng)目的時(shí)候俺猿,總是想著找一些好用的東西,讓我們的的項(xiàng)目兼容性更好五嫂,效率更高箫柳,運(yùn)行速度更快,當(dāng)然寫代碼也要更舒服牺蹄。
抽了一點(diǎn)時(shí)間研究了一下MVP,并且用Swift方式實(shí)現(xiàn)了一遍薄翅,雖然只是一個(gè)例子沙兰,但是還是感覺(jué)到MVP的模型數(shù)據(jù)分離真的很好。
需要用到的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協(xié)議匿刮,定義了一個(gè)屬性view僧凰, 和一個(gè)函數(shù)initial。
view的作用最后就是你傳進(jìn)來(lái)的Controller熟丸。initial的作用是為了給view賦值训措,并且初始化一個(gè)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設(shè)置了一個(gè)代理屬性responseHandle绩鸣,通過(guò)init函數(shù)給它賦值從而達(dá)到在CachePresenter里可以回調(diào)到它的兩個(gè)函數(shù)。get函數(shù)就是從服務(wù)器獲取數(shù)據(jù)纱兑。
HTTPResponseProtocol.swift
protocol HTTPResponseProtocol {
func onSuccess(object: Dictionary<String, Any>)
func onFailure(error: Error)
}
HTTPResponseProtocol定義了兩個(gè)函數(shù)需要你去實(shí)現(xiàn)呀闻,一個(gè)是成功一個(gè)是失敗。
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
}
}
網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù)用的是httpbin.org的一個(gè)測(cè)試請(qǐng)求返回的數(shù)據(jù)
http://httpbin.org/cache/2000
CacheModel定義了兩個(gè)屬性和一個(gè)靜態(tài)函數(shù)潜慎。
CacheProtocol.swift
protocol CacheProtocol {
func onGetCacheSuccess(model: CacheModel?)
func onGetCacheFailure(error: Error)
}
CacheProtocol是Controller遵從的協(xié)議捡多,只有Controller遵從了這個(gè)協(xié)議,才能拿到從服務(wù)器拿到的CacheModel的值铐炫。
CachePresenter.swift (重點(diǎn))
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) {
// 網(wǎng)絡(luò)請(qǐng)求 ...
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類指定了一個(gè)泛型U垒手, U指定了必須是實(shí)現(xiàn)了CacheProtocol協(xié)議的類,我們知道上面我們說(shuō)到實(shí)現(xiàn)CacheProtocol的類是Controller倒信。
- 之后我們實(shí)現(xiàn)了Presenter協(xié)議的屬性和函數(shù)分別給它賦值科贬,上面我們說(shuō)了在inital函數(shù)里初始化了httpClient并且它的responseProtocol是CachePresenter。
- 實(shí)現(xiàn)HTTPResponseProtocol協(xié)議 onSuccess, onFailure
最后我們的get函數(shù)拿到的數(shù)據(jù)并把數(shù)據(jù)代理到當(dāng)前的onSuccess函數(shù)鳖悠,然后我們的Presenter的view是一個(gè)CacheProtocol榜掌,所以它可以調(diào)用onGetCacheSuccess优妙,然后CacheProtocol又是Controller實(shí)現(xiàn)的,最后就完成了一個(gè)閉環(huán)憎账。
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() {
// 請(qǐng)求網(wǎng)絡(luò)
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函數(shù)。在reloadData里調(diào)用get函數(shù)從服務(wù)器獲取數(shù)據(jù)鼠哥,最后經(jīng)過(guò)CachePresenter拿到代理函數(shù)熟菲,最后將數(shù)據(jù)賦值給Label顯示。
最重要的類是CachePresenter它負(fù)責(zé)獲取數(shù)據(jù)朴恳,并和model,view進(jìn)行交互允蚣。
-- Finished --
參考:
- http://www.reibang.com/p/abea207c23e7 OC版本
- https://baike.baidu.com/item/MVP%E6%A8%A1%E5%BC%8F/10961746?fr=aladdin 百度百科
其他:
- 在Swift版本里做了一些優(yōu)化丟掉了HttpPresenter這個(gè)類于颖。
- https://github.com/hellolad/Swift-MVP SwiftMVP Demo地址