관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 1.modern MVC (with coordinator) 개념 본문

Architecture (swift)/MVC (with coordinator)

[iOS - swift] 1.modern MVC (with coordinator) 개념

jake-kim 2021. 4. 29. 01:52

MVC 구성

  • View는 Controller와 상호작용 하지만, Controller의 인터페이스를 알지 못하며 직접 호출하지 않는 구조
  • MVC끼리의 통신

MVC

  • 애플의 지향: 최소한의 구성 요소만 포함
  • old MVC의 한계: Massive ViewController, DI 프로그래밍 x, 프로토콜 지향 프로그래밍 x
  • 한계 극복
    • Delegate, DataSource를 Model에 두고, ViewController 비즈니스 로직을 간소화 
    • Coordinator가 포함된 MVC패턴

MVC의 원칙

  • Model: 앱의 데이터
    • 네트워크 코드: 네트워크 통신은 되도록 단일 클래스 사용
    • 지속성 코드: DB, Core Data
    • 코드 파싱: codable
    • Manager 클래스 (=Wrapper class)
    • DataSource, Delegate, CompletionBlock
    • 상수: 포멧터, 색상 이름
    • extension 코드
  • View: 비즈니스 로직을 포함하지 않는 UI 표출, 재사용 할수 있도록 모든 뷰를 generic으로 구현
    • UIView하위 클래스
    • UIKit에 속하는 클래스
    • 애니메이션
    • 그래픽
  • Controller (= 두뇌): 가장 재사용하기 어려운 부분이며 비즈니스 로직을 담당
    • 다음 화면은 무엇이고 어떤 상황에 있어야 하는지?
    • 앱을 얼마나 새로 고침 해야하는지?
    • 앱이 백그라운드로 이동하면 무엇을 해야하는지?
    • 사용자가 셀틀 탭했을 때 다음에 무엇을 해야하는지?

modern MVC

  • ViewController를 줄이는 접근: DataSource, Delegate 역할을 하는 별도의 클래스를 만들어서 Model에 배치하여 더욱 단순화
    • ViewController / UIController / Controller 세 개를 분리하여 코딩 
    • 소스코드
  • 아키텍처보다는 SOLID 원칙에 집중
    • Single-responsiblity principle
    • Open-closed principle
    • Liskov substitution principle
    • Interface segregation principle
    • Dependency inversion principle

MVC with Coordinator

  • Controller에 필요한 기능은 Coordinator에서 주입
  • controller들의 화면전환은 Coordinator의 delegate로 할당

Coordinator를 쓰지 않은 경우 - 두번째 Controller는 Downloading에 의존

  • Coordinator의 핵심: MVC간 서로의 정보를 모르고 있는 상태
    • 만약 Coordinator가 없다면 첫 번째 Controller가 두 번째 Controller에 의존하고 있어서, 두 번째 Controller를 갈아 끼우기 힘든 형태

Coordinator를 이용한 경우: (delegate 구현부 - Coordinator, delegate 사용 - Controller)

cf) Delegate를 사용하여 의존성을 없애는 핵심 개념

  • Delegate 구현된 것을 사용하는 입장에서는 실선이 아닌 점선이 되는 효과
    • delegate의 구현부는 모르고 그냥 사용하는 형태
    • delegate weak var이며 memory leak방지 형태
    • 위 사진에서는, Coordinaotor가 delegate구현부이고 Controller들이 delegate 사용하는 입장
    • Coordinator 모듈화가 되어, Coordinator를 갈아 끼우기 쉬운 형태
    • 각 Controller들의 Delegate가 있으며, Coordinator는 해당 Delegate의 구현체이며, 각 Controller들은 이 구현체가 주입되는 형태
  • Coordinator 코드 
    • FirstControllerDelegate를 통해, FirstViewController에서 해당 delegate 구현체를 이용하여 화면전환
    • 사용하는 입장에서 어디로 이동하는지 모르고, 단순히 상태에 관해 호출 run(), onAction() 하면 알아서 Coordinator에서 이동되도록 구현 -> 화면전환 로직은 오로지 Coordinator에서 실행
    • 데이터 전달은 각 ViewController안에 dependency struct를 만들어서 주입
class Coordinator: FirstControllerDelegate {
    let window: UIWindow
    var navigation: UINavigationController?
    
    lazy var firstViewController: FirstViewController = {
        let controller = FirstViewController()
        controller.delegate = self
        return controller
    }()
    
    lazy var secondViewController: SecondViewController = {
        let downloader = DownloadController()
        let controller = SecondViewController(downloader: downloader)
        controller.delegate = self
        return controller
    }()
    
    init(window: UIWindow) {
        self.window = window
    }

    func run() {
        self.navigation = UINavigationController(rootViewController: self.firstViewController)
        self.window.rootViewController = self.navigation
    }
    
    func onAction() {
        self.navigation?.pushViewController(self.secondViewController, animated: true)
    }
}

cf) 프로토콜 지향 프로그래밍의 장점

  • reference type -> value type: enum, struct와 같은 ValueType도 상속의 효과를 줄 수 있다는 의미
  • testable code
  • 컴파일 오류로 구현해야 할 것을 명확히 알려주는 안전한 프로그래밍

* 참고

medium.com/ios-os-x-development/modern-mvc-39042a9097ca

Martin Fowler. Application Controller

Apple Developer Library. Cocoa Core Competencies

Matt Gallagher. Looking at Model-View-Controller in Cocoa

Soroush Khanlou. 8 Patterns to Help You Destroy Massive View Controller

www.raywenderlich.com/1000705-model-view-controller-mvc-in-ios-a-modern-approach

Comments