VM 및 MVP 모드

15951 단어 Swift

소개


응용 프로그램을 만들 때 여러 가지 생각이 있는데 그 중에서 특히 중요한 것은 디자인 모델의 선정이다.
저는 지금까지 주로 MVVM 모드로 설치했지만 예전부터 MVP에 관심이 많아서 샘플 앱을 만들면서 장점과 단점을 살펴봤습니다.
참고로 읽었습니다iOS 응용 프로그램 설계 모드 시작.각 장의 내용은 매우 간결하고 이해하기 쉬우며 읽기 쉽기 때문에 상당히 추천하는 저작이다.

VVM이란 무엇입니까?


한마디로 GUI의 구조는 모델,View,ViewModel 세 가지 모델로 나뉜다.
이러한 기능은 다음과 같습니다.
  • Model - 디스플레이와 무관한 도메인 논리
  • View-사용자 작업을 수락하고 ViewModel 상태 변경을 모니터링하며 화면 업데이트
  • ViewModel - 전체 화면 디스플레이와 관련된 논리로 View용 데이터 저장

  • 그림에서 보듯이 참조 관계는 단방향이며 상반된 참조 관계는 없다.이벤트는 모델, 뷰 모델에 대한 변경 사항을 알려 줍니다.
    VM 모드의 가장 큰 특징은 데이터 바인딩을 통해 보기를 업데이트하는 것이다.
    논리는 프로그램적이지 않고 성명적으로 표시할 수 있기 때문에 구성 요소 간에 느슨한 결합을 유지할 수 있다.이로써 가독성과 테스트성을 높인다.
    이 데이터 귀속 기구는 RxSwift와ReactiveSwit 등 라이브러리를 사용하지만 이쪽의 개념 이해에 드는 비용이 매우 높은 것도 특징 중 하나이다.

    MVP


    한마디로 GUI의 구조를 모델,View,Presenter 세 가지 모델로 나눈다.
    모델의 역할은 MVVM과 같습니다.
  • Model - 디스플레이와 무관한 도메인 논리
  • View - 사용자 작업을 수락하고 Presenter에 처리를 전달합니다.Presenter에서 화면 업데이트 지시를 받고 화면 업데이트
  • Presenter-Model 및View의 중개 역할입니다.화면 표시 논리 있음

  • Passive View와 Supervising Controller 두 가지 View 업데이트 방법이 있습니다. 이번에는 그림의 Passive View를 전제로 합니다.Passive View는 데이터 흐름을 추적하기 쉬우며 간단한 처리는 모델과 관련될 때도 다음과 같은 절차를 준수해야 한다.
    View → Presenter → Model → Presenter → View
    
    따라서 코드의 군더더기를 일으키기 쉬운 측면도 있다.
    그러나 모든 프레젠테이션 논리를 Presenter에 제한할 수 있어 테스트의 용이성을 높일 수 있다.

    VVM 및 MVP 비교


    우선, MVVM과 MVP의 공통점은 구성 요소가 느슨하게 결합되어 테스트의 용이성과 가독성을 높인다는 것이다.
    말하자면 왜 이렇게 해야 합니까?
    이는 애플이 제창한 코코카 MVC 모델에서View Controller의 역할이 너무 커서 가독성, 테스트 용이성이 낮아져 이른바 Fat View Controller가 되기 쉽다.
    따라서 MVVM과 MVP 등의 모델을 사용하여 책임을 분리하여 이러한 문제를 해결한다.
    VVM과 MVP의 차이를 실감하기 위해 처음에 소개한 저서의 샘플 코드를 바탕으로 MVVM과 MVP 각자의 디자인으로 샘플 응용 프로그램을 만들어 보았다.
    Github 사용자를 검색하고 사용자의 저장소 목록을 표시합니다.
    데이터는 실제 API 통신을 하지 않고 모크에서 얻은 것이다.
    사용자 검색
    저장소 표시


    본고는 SearchBar에 문자 표시 대상 사용자의 부분을 입력하여 MVVM, MVP 각자의 모델로 실시하는 부분을 소개한다.자료 라이브러리에 대한 표시는 마지막으로 샘플 코드의 URL이 기재되어 있으니 관심 있는 사람이 볼 수 있다면 좋겠다.
    우선 MVP의 설치를 살펴보겠습니다.
    Presenter의 실현에서 먼저 프로토콜에서 Input/Output의 처리를 선언합니다.
    ViewController에서 이관된 Input를 처리하고 Output에서 처리를 모델에 이관하며 결과를 ViewController에 다시 전달합니다.
    // SearchUserPresenter
    protocol SearchUserPresenterInput {
        var numberOfUsers: Int { get }
        func user(forRow row: Int) -> User?
        func didSelectRow(at indexPath: IndexPath)
        func didTapSearchButton(text: String?)
    }
    
    protocol SearchUserPresenterOutput: AnyObject {
        func updateUsers(_ users: [User])
        func transitionToUserDetail(userName: String)
    }
    
    final class SearchUserPresenter: SearchUserPresenterInput {
    
        ...
    
        func didTapSearchButton(text: String?) {
            guard let query = text { return }
            model.fetchUser(query: query) { [weak self] result in
                switch result {
                case .success(let users):
                    self?.users = users
                    DispatchQueue.main.async {
                        self?.view.updateUsers(users)
                    }
                case .failure:
                    ()
                }
            }
        }
    
    ...
    
    }
    
    ViewController는 Output 프로토콜을 구현하여 화면을 업데이트합니다.
    // SearchUserViewController.swift
    
    extension SearchUserViewController: SearchUserPresenterOutput {
        func updateUsers(_ users: [User]) {
            tableView.reloadData()
        }
    
        ...
    
    }
    
    이로써 방금 설명한 다음과 같은 절차를 실현하였다.
    View → Presenter → Model → Presenter → View
    
    이제 MVVM에서의 구현을 살펴보겠습니다.
    ViewModel은 View의 입력에 응답하여 등록 정보 사용 을 업데이트합니다.
    여기서 View에서 실행(입력)search() 방법을 통해 모델은 데이터를 처리하고 결과를state에 연결합니다.
    final class SearchUserViewModel {
        let state = BehaviorRelay<[User]?>(value: nil)
        private let model: SearchUserModel
        private let disposeBag = DisposeBag()
    
        init(model: SearchUserModel) {
            self.model = model
        }
    
        func search(query: String) {
            model.fetch(query: query)
                .asObservable()
                .bind(to: state)
                .disposed(by: disposeBag)
        }
    }
    
    View에서 미리 모니터링 객체를 설정하고 ViewModel의 이벤트 알림에 따라 화면을 업데이트합니다.
    final class SearchUserViewController: UIViewController {
    
        ...
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            viewModel = SearchUserViewModel(model: SearchUserModel())
            tableView.registerCell(type: SearchUserCell.self)
    
            viewModel.state.subscribe(onNext: { [unowned self] _ in
                self.tableView.reloadData()
            }).disposed(by: disposeBag)
        }
    }
    
    ...
    
    extension SearchUserViewController: UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            guard let state = viewModel.state.value else { return 0 }
            return state.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueCell(type: SearchUserCell.self, indexPath: indexPath)
            guard let state = viewModel.state.value else { return cell }
            cell.configure(user: state[indexPath.row])
            return cell
        }
    }
    

    VVM과 MVP로 각각 실시한 소감


    우선 MVP가 프레젠테이션 논리의 실현을 할 때 "View와 Model 각자의 일을 고려해야 한다"는 것을 처음 느꼈다.마음에 걸려요.
    앞에서 설명한 대로 Presenter는 중개 역할입니다.
    따라서 Presenter를 실시할 때 View와 Model 각자의 안색을 보면서 실시해야 한다.
    한편, MVVM은 프레젠테이션 논리를 실현할 때 모델에서 얻은 데이터를 어떻게 성형하는지에만 전념한다.
    코드를 보면 알 수 있듯이 코드의 양도 각기 다르고 MVP가 비교적 많다.
    이것은 앞에서 말한 바와 같이 코드가 지루하게 변할 수 있음을 나타낸다.

    총결산


    이번에 실제로 MVVM, MVP 모드에서 샘플 응용 프로그램을 설치하여 각자의 장단점을 비교하여 다음과 같이 하였다.

    MVVM


    이점
  • View, ViewModel, Model은 단방향 참조 관계이므로 분산 결합을 유지하고 각각의 작업에 집중할 수 있음
  • 각 구성 요소의 작업 분담이 명확하기 때문에 군더더기 코드가 생기지 않고 비교적 적은 코드량
  • 결점
  • RxSwift, ReactiveSwift 등 라이브러리는 필수이기 때문에 초기 설정이 번거롭다
  • FRP 개념을 이해하기 전의 학습 비용이 비교적 높다
  • MVP


    이점
  • 초기 배포 불필요
  • 특별한 설치가 필요하지 않기 때문에 이미 MVC 등에 설치된 항목도 가져오기 쉽다
  • 결점
  • 데이터 흐름 요구가 엄격하고 코드가 번거롭기 쉽다
  • 코드량 증가, 설치비
  • 예제 코드

  • VM 모드
  • MVP 모드
  • 좋은 웹페이지 즐겨찾기