Sök…


Introduktion

MVP är ett arkitektoniskt mönster, en härledning av Model – View – Controller. Det representeras av tre distinkta komponenter: Model, View och Presenter. Den var konstruerad för att underlätta automatiserad enhetstestning och förbättra separationen av oro i presentationslogiken.

I exempel hittar du ett enkelt projekt byggt med MVP-mönster i åtanke.

Anmärkningar

Komponenter:

ange bildbeskrivning här

  • Modellen är ett gränssnitt som ansvarar för domändata (visas eller på annat sätt genomförs i GUI)
  • View ansvarar för presentationslagret (GUI)
  • Presentatören är "mellanmannen" mellan Model och View. Den reagerar på användarens handlingar som utförs i vyn, hämtar data från modellen och formaterar dem för visning i vyn

Komponentuppgifter:

Modell Se Presentatör
Kommunicerar med DB-lager Renderar data Utför frågor till modellen
Att höja lämpliga händelser Tar emot händelser Formaterar data från modell
Mycket grundläggande valideringslogik Skickar formaterad data till vyn
Komplex valideringslogik

Skillnader mellan MVC och MVP :

  • Vy i MVC är tätt kopplat till Controller, View-delen av MVP består av både UIViews och UIViewController
  • MVP View är så dumt som möjligt och innehåller nästan ingen logik (som i MVVM). MVC View har viss affärslogik och kan fråga modellen
  • MVP View hanterar användares gester och delegerar interaktion till presentatören, i MVC hanterar kontroller gester och kommandon Model
  • MVP-mönster stöder starkt enhetstestning, MVC har begränsat stöd
  • MVC Controller har många UIKit-beroenden, MVP Presenter har ingen

Fördelar:

  • MVP gör UIViewController till en del av View-komponenten, den är dum, passiv och ... mindre massiv;]
  • De flesta av affärslogiken är inkapslade på grund av dumma åsikter, vilket ger en utmärkt testbarhet. Mocka objekt kan introduceras för att testa domändelen.
  • Separerade enheter är lättare att hålla huvudet, ansvaret är tydligt uppdelat.

Nackdelar

  • Du kommer att skriva mer kod.
  • Barriär för oerfarna utvecklare eller för de som ännu inte arbetar med mönstret.

Dog.swift

import Foundation

enum Breed: String {
    case bulldog  = "Bulldog"
    case doberman = "Doberman"
    case labrador = "Labrador"
}

struct Dog {
    let name:  String
    let breed: String
    let age:   Int
}

DoggyView.swift

import Foundation

protocol DoggyView: NSObjectProtocol {
    func startLoading()
    func finishLoading()
    func setDoggies(_ doggies: [DoggyViewData])
    func setEmpty()
}

DoggyService.swift

import Foundation

typealias Result = ([Dog]) -> Void

class DoggyService {

    func deliverDoggies(_ result: @escaping Result) {
        
        let firstDoggy  = Dog(name: "Alfred", breed: Breed.labrador.rawValue, age: 1)
        let secondDoggy = Dog(name: "Vinny",  breed: Breed.doberman.rawValue, age: 5)
        let thirdDoggy  = Dog(name: "Lucky",  breed: Breed.labrador.rawValue, age: 3)

        let delay = DispatchTime.now() + Double(Int64(Double(NSEC_PER_SEC)*2)) / Double(NSEC_PER_SEC)
        
        DispatchQueue.main.asyncAfter(deadline: delay) {
            result([firstDoggy,
                    secondDoggy,
                    thirdDoggy])
        }
    }
}

DoggyPresenter.swift

import Foundation

class DoggyPresenter {

    // MARK: - Private
    fileprivate let dogService: DoggyService
    weak fileprivate var dogView: DoggyView?

    init(dogService: DoggyService){
        self.dogService = dogService
    }

    func attachView(_ attach: Bool, view: DoggyView?) {
        if attach {
            dogView = nil
        } else {
            if let view = view { dogView = view }
        }
    }

    func getDogs(){
        self.dogView?.startLoading()
    
        dogService.deliverDoggies { [weak self] doggies in
            self?.dogView?.finishLoading()
        
        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:  String
}

DoggyListViewController.swift

import UIKit

class DoggyListViewController: UIViewController, UITableViewDataSource {

    @IBOutlet weak var emptyView: UIView?
    @IBOutlet weak var tableView: UITableView?
    @IBOutlet weak var spinner:   UIActivityIndicatorView?

    fileprivate let 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()
    }

    // MARK: DataSource
    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: [DoggyViewData]) {
        dogsToDisplay = doggies
        tableView?.isHidden = false
        emptyView?.isHidden = true;
        tableView?.reloadData()
    }

    func setEmpty() {
        tableView?.isHidden = true
        emptyView?.isHidden = false;
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow