MVP is an architectural pattern, a derivation of the Model-View-Controller. It's represented by three distinct components: Model, View and the Presenter. It was engineered to facilitate automated unit testing and improve the separation of concerns in presentation logic.
Example:
// MARK: Dog.swift
import Foundation
enum Breed:String {
case bulldog = "BullDog"
case doberman = "Doberman"
case labrador = "Labrador"
}
structDog {
let name:String
let breed:String
let age:Int
}
// DoggyPresenter.swift
import Fundation
class DoggyPresenter {
// MARK: - private
fileprivate let dogService: DogService
weak fileprivate var dogView: DoggyView?
init(dogService: DogService) {
self.dogService = dogService
}
func attachView(_ attach: Bool, view: DoggyView?) {
if attach {
dogView = nil
} else {
if let view = view {
dogView = view
}
}
}
// MARK: get dogs
func getDogs() {
self.dogView?.startLoading()
dogService.deliverDoggies { [weak self] doggies in
self?.dogView?.stopLoading()
if doggies.count == 0 {
self?.dogView?.setEmpty()
} else {
self?.dogView?.setDoggies(doggies.map {
return DoggyViewData(name : "\($0.name) \($0.breed)", age : "\($0.age)")
})
}
}
}
}
struct DoggyViewData {
let name : String
let age : Int
}
// MARK: - DoggyServices.swift
import Foundation
typealias Result = ([Dog]) -> Void
class DoggyServices {
func deliverDoggies(_ result: @escaping Result) {
let firstDoggy = Dog(name: "", breed: Breed.bulldog.rawValue, age: 1)
let secondDoggy = Dog(name : "", breed: Breed.doberman.rawValue, age: 5)
let thirdDoggy = Dog(name: "", breed: Breed.labrador.rawValue, age: 7)
let delay = DispatchTime.now() + Double(Int64(Double(NSEC_PER_SEC)*2)) / Doubel(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delay) {
return result([firstDoggy, secondDoggy, thirdDoggy])
}
}
}
// MARK: -- DoggyListViewController
import UIKit
class DoggyListViewController : UIViewController, UITableViewDataSource {
@IBOutlet weak var emptyView: View?
@IBOutlet weak var tableView: UITableView?
@IBOutlet weak var spinner: UIActivityIndicatorView?
fileprivate dogPresenter = DoggyPresenter(dogService: DoggyService())
fileprivate var dogsToDisplay = [DoggyViewData]()
override func viewDidLoad() {
super.viewDidLoad()
tableView?.dataSource = self
spinner?.hidesWhenStopped = true
dogPresenter.attachView(true, view: self)
dogPresenter.getDogs()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dogsToDisplay.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style:.subtitle, reuseIdentifier:"Cell")
let userViewData = dogsToDisplay[indexPath.row]
cell.textLabel?.text = userViewData.name
cell.detailTextLabel?.text = userViewData.age
return cell
}
extension DoggyListViewController: DoggyView {
func startLoading() {
spinner?.startAnimating()
}
func finishLoading() {
spinner?.stopAnimating()
}
func setDoggies(_ doggies: [DogViewData]) {
dogsToDisplay = doggies
tableView?.isHidden = false
emptyView?.isHidden = true
tableView?.reloadData()
}
func setEmpty() {
tableView?.isHidden = true
emptyView?.isHidden = false
}
}
// DoggyView.swift
import Fundation
protocol DoggyView: NSObjectProtocol {
func startLoading()
func finishLoading()
func setDoggy(_ doggies: [DoggyViewData])
func setEmpty()
}
// MARK: -- Attention
Model is an interface responsible for the domain data ( to be displayed or otherwise acted upon in the GUI )
View is responsible for the presentation layer ( GUI )
Presenter is the "middle-man" between Model and View. It reacts to the user's actions performed on the View, retrieves data from the Model, and formats it for display in the View.
Component duties:
1. Model
communicate with DB layer ;
Raising appropriate actions;
2. View
Renders data;
Receives events;
Very basic validation logic;
3. Presenter
Performs queries to the model;
Formats the data from the model;
Sends formatted data to the view;
Complex validation logic;
// MARK: Difference between MVC and MVP
1. View in MVC is tightly coupled with the Controller, the View part of the MVP consists of both UIViews and UIViewController.
2. MVP view is as dumb as possible and contains almost no logic(like in MVVM), MVC View has some businesss logic and can query the Model.
3. MVP View handles user gestures and delegates interaction to the Presenter, in MVC the Controller handles gestures and commands Mpdel.
4. MVP pattern highly supports Unit Testing. MVC has limited support.
5. MVP Controller has lots of UIKit dependencies, MVP Presenter has none.
// MARK: Pros
1. MVP makes UIViewController a part of the View components it's dumb, passive and ... less massive;
2. Most of the business logic is incapsulated due to the dumb Views, this gives an excellent testability.Mock objects can be introduced to test the domain part.
3. Separated entities are easier to keep in head, responsibilities are clearly divided.
网友评论