MVP 全称:Model-View-Presenter ;MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。
protocol IView {
}
protocol IModel {
}
protocol IPresenter {
var mView: View? { get set }
var mModel: Model? {get set}
associatedtype View:IView
associatedtype Model:IModel
func bindView( _ iView:View)
func unBind()
}
class BasePresenter<T:IView, M:IModel>: IPresenter{
var mModel: M?
var mView: T?
func bindView(_ iView: T) {
mView = iView
}
func unBind() {
}
typealias View = T
typealias Model = M
}
class BaseView:IView{}
class BaseModel: IModel {
}
class AModel:IModel{
func doCallback( back:()->Void){
print("model do it to pass to view")
back()
}
}
protocol AView: IView {
func doIt()
}
class MyPresenter: BasePresenter<MyViewController, AModel>{
func doIt(){
print("presenter do it to call model")
if self.mModel == nil {
self.mModel = AModel()
}
mModel?.doCallback {
mView?.doIt()
}
}
}
class MyViewController : UIViewController, AView{
func doIt() {
print("view do it")
}
var mPresenter: MyPresenter?
override func loadView() {
mPresenter = MyPresenter()
defer {
mPresenter?.unBind()
mPresenter = nil
}
mPresenter?.bindView(self)
print("start call presenter")
mPresenter?.doIt()
let view = UIView()
view.backgroundColor = .white
let label = UILabel()
label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.text = "Hello World!"
label.textColor = .black
view.addSubview(label)
self.view = view
}
}
MVP中我们把个个分开没有形成一个整体,我们完全可以把MVP哥哥部分统一的进行一个整体的集合,通过声明Contract将其整合到一起,将P的初始化和基本操作绑定等交给contract,通过contract与UIViewController的交互
protocol Contract{
associatedtype Model
associatedtype View
associatedtype Presenter
var mModel:Model?{get set}
var mView: View? {get set}
var mPresenter: Presenter?{get set}
func doViewBindToPresenter()->Bool
func doViewUnBindtFromPresenter()
}
然后声明一个基类来完成mvp通用的逻辑处理
class BaseContract<M:IModel, V:IView,P:BasePresenter<V, M>>: Contract {
var mModel: M?
var mView: V?
var mPresenter: P?
typealias Model = M
typealias View = V
typealias Presenter = P
func doViewUnBindtFromPresenter() {
mPresenter?.unBind()
}
func doViewBindToPresenter() -> Bool {
if mView == nil || mPresenter == nil{
return false
}
mPresenter?.bindView(mView!)
return true
}
init( v:V, p:(V)->P) {
mView = v
mPresenter = p(mView!)
}
}
最后根据实际的需要进行contract的扩展
class AContract:BaseContract<AModel, MyViewController , BasePresenter<MyViewController, AModel>>{
}
让我们看看怎么使用
override func loadView() {
var a = AContract.init(v: self) { (vc:MyViewController) -> BasePresenter<MyViewController, AModel> in
var p = MyPresenter.init()
p.bindView(vc)
p.doIt()
return p
}
// mPresenter = MyPresenter()
// defer {
// mPresenter?.unBind()
// mPresenter = nil
// }
// mPresenter?.bindView(self)
// print("start call presenter")
// mPresenter?.doIt()
let view = UIView()
view.backgroundColor = .white
let label = UILabel()
label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.text = "Hello World!"
label.textColor = .black
view.addSubview(label)
self.view = view
}