之前我们聊过MVP的,也简单写了个人采用swft版本MVP,今天我们结合实例进行简单优化实践……
talk is cheap ,show you code
public protocol IView {}
public protocol IPresenter {
associatedtype View: IView
var mView: View? {get}
func bind(to view: View)
}
public protocol Contract {
associatedtype Presenter: IPresenter
associatedtype View: IView
var presenter: Presenter? {get}
func bind( _ view: View)
}
代码中我们定义了Presenter View 协议,然后让Contract进行统一管理。也许你会疑问为啥让Contract来处理?其实从字面意思就可以看出Contract有契约之意。也就是说咱们想使用就要遵循这个契约……
接下来我们来做一些基础性的事情:
到目前为止我们看到所有的都是不能实例化的协议。那么MVP我们从哪个开始入手呢?当然是主角P啦--MVP的模式就是将MVC中的C复杂逻辑主战场移动到了P中……而对于P来说势必会持有:View 和 负责对View的绑定,于是……下面的P的基类应运而生
public class BasePresenter<V>:NSObject, IPresenter where V: IView{
public func bind(to view: View) {
mView = view
}
public typealias View = V
public var mView: View?
func getView()->V?{
return mView
}
}
BasePresenter作为IPresenter的基础逻辑扩充,同时负责从C中View的绑定,最终完成交互C=>P=>V=>C的一个完成闭环…
万事具备,下面我们看看怎么完成一个简单的MVP流程……在展示流程的时候我们先看看基本的项目结构
我们把Contract Presenter View分别单独出来,然后完成自己影有的逻辑……我们结合?按照View Presenter Contract的顺序来讲解
1 View
protocol MainMenuIView: IView {
func onMainItemSelected(mainMenu: MainMenu)
}
extension MainMenuViewController: MainMenuIView{
func onMainItemSelected(mainMenu: MainMenu) {
}
}
这个View很简单就是实现一个TableView点击的响应传递,此处我们将ViewController作为MVP中的View,而Controller只需要接受MVP传递的数据和事件完成UI的跳转控制即可----逻辑和事件数据交个MVP,而Controller只需要页面跳转穿插即可
2 Presenter
class MainMenuPresenter: BasePresenter<MainMenuViewController> {
func onMainItemSelected(mainMenu: MainMenu){
getView()?.onMainItemSelected(mainMenu: mainMenu)
}
override func bind(to view: MainMenuViewController) {
super.bind(to: view)
getView()?.mainMenuTableView.dataSource = self
getView()?.mainMenuTableView.delegate = self
}
}
extension MainMenuPresenter : NSTableViewDelegate {
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let tableViewCell:NSTableCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier.init("main_menu_cell"), owner: self) as! NSTableCellView
tableViewCell.textField?.stringValue = "xxxxxxx"
return tableViewCell
}
func tableView(_ tableView: NSTableView, dataCellFor tableColumn: NSTableColumn?, row: Int) -> NSCell? {
return nil
}
func numberOfRows(in tableView: NSTableView) -> Int {
return 3
}
}
extension MainMenuPresenter : NSTableViewDataSource{
func tableViewSelectionDidChange(_ notification: Notification) {
}
}
Presenter比较复杂啦,除了需要对VIew进行绑定,同时需要对UI进行一些数据的初始化,负责View的交互和PV事件的传递…
例如此处:TableVIew的点击事件或调用Presenter的func onMainItemSelected(mainMenu: MainMenu)然后Presnter将事件传递给View的实例来完成事件与数据的传递
3 Contract
protocol MainMenuViewControllerContract: Contract where View == MainMenuViewController ,Presenter == MainMenuPresenter {}
extension MainMenuViewController : MainMenuViewControllerContract{
var presenter: MainMenuPresenter? {
return self.mainPresenter
}
func bind(_ view: MainMenuViewController) {
presenter?.bind(to: self)
self.mainMenuTableView.delegate = presenter
self.mainMenuTableView.dataSource = presenter
}
}
Contract是MVP的灵魂契约,在这里简单的一行代码
protocol MainMenuViewControllerContract: Contract where View == MainMenuViewController ,Presenter == MainMenuPresenter {}
我们让Presenter IView知道了各自的具体类型,然后将P V进行绑定穿插完成一个基本的MVP闭环……
最后让我们看看显示结果完成咱们今天的小实例