サーチ…


前書き

MVPは、Model-View-Controllerの派生物であるアーキテクチャパターンです。モデル、ビュー、およびプレゼンターの3つの異なるコンポーネントによって表されます。自動化されたユニットテストを容易にし、プレゼンテーションロジックにおける懸念の分離を改善するために設計されました。

例では、MVPパターンを念頭に置いた簡単なプロジェクトを見つけるでしょう。

備考

コンポーネント:

ここに画像の説明を入力

  • モデルは、ドメインデータ(GUIに表示されるか、さもなければ動作する)を担当するインターフェースであり、
  • ビューはプレゼンテーション層(GUI)を担当し、
  • PresenterはModelとViewの中間的な人物です。これは、ビューで実行されたユーザーのアクションに反応し、モデルからデータを取得し、ビューに表示するためにフォーマットします

コンポーネントの任務:

モデルビュープレゼンター
DB層と通信するデータをレンダリングするモデルへのクエリを実行します。
適切なイベントの提起イベントを受け取るモデルからデータをフォーマットする
非常に基本的な検証ロジックフォーマットされたデータをビューに送信します。
複雑な検証ロジック

MVCとMVPの 違い

  • MVCのビューはコントローラと密接に結合されており、MVPのビュー部分はUIViewとUIViewControllerの両方で構成されています
  • MVP Viewは可能な限りダムであり、MVVMのようなロジックはほとんど含まれていないため、MVC Viewにはビジネスロジックがあり、モデルをクエリできます
  • MVPビューでは、ユーザーのジェスチャーを処理し、プレゼンターとの対話を委任します。MVCでは、コントローラーがジェスチャーとコマンドを処理します。モデル
  • MVPパターンは高度にユニットテストをサポートし、MVCは限られたサポートを持っています
  • MVC Controllerには多くのUIKit依存関係があり、MVP Presenterには何もありません

長所:

  • MVPはUIViewControllerをViewコンポーネントの一部にしています。
  • ビジネスロジックのほとんどは、ダムビューのためにカプセル化されています。これは優れたテスト容易性を提供します。 Mockオブジェクトを導入してドメイン部分をテストすることができます。
  • 分離されたエンティティは頭に入れやすいので、責任は明確に分かれています。

短所

  • より多くのコードを書くでしょう。
  • 経験の浅い開発者やパターンをまだ使用していない人のための障壁。

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
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow