iOS Architecture Patterns

Lena·2020년 12월 14일
0
post-custom-banner

MVC

  • Models — 데이터나 데이터 접근 레이어(Person 클래스나 PersonDataProvider 클래스와 같이 데이터를 다루는)의 책임이 있다.
  • Views — responsible for the presentation layer (GUI), 'UI'가 prefix로 붙는 것들에 대한 책임이 있다(UIButton, UILable, ...).
  • Controller/Presenter/ViewModel — Model과 View 사이를 연결한다. View에서 유저 액션에 대한 Model을 변경하거나, Model이 변경되었을 때 View를 갱신한다.

개체를 나누는 것은:

  • 코드를 더 잘 이해할 수 있고 (as we already know),
  • 재사용할 수 있으며 (mostly applicable to the View and the Model),
  • 독립적으로 테스트할 수 있다.

MVC의 간단한 예제는 다음과 같다.

import UIKit

struct Person { // Model
    let firstName: String
    let lastName: String
}

class GreetingViewController : UIViewController { // View + Controller
    var person: Person!
    let showGreetingButton = UIButton()
    let greetingLabel = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside)
    }
    
    func didTapButton(button: UIButton) {
        let greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
        self.greetingLabel.text = greeting
        
    }
    // layout code goes here
}
// Assembling of MVC
let model = Person(firstName: "David", lastName: "Blaine")
let view = GreetingViewController()
view.person = model

MVC는 View와 Controller를 각각 테스트하기 어렵다. View와 Controller가 강하게 결합되어 있어서(viewDidLoad, didTapButton) 따로 분리해서 테스트하기 어렵다.

The interactions between the View and the Controller aren’t really testable with Unit Tests

MVC 패턴은 다른 패턴에 비해 코드가 적게 들기 때문에 개발 속도면에서는 좋은 선택이 될 수 있다.

MVVM

  • Model — MVVM의 Model과 View는 연결되어 있지 않다.
  • View — MVVM에서는 ViewController를 View로 다룬다.
  • ViewModel — View와 Model 사이의 중개자
import UIKit

struct Person { // Model
    let firstName: String
    let lastName: String
}

protocol GreetingViewModelProtocol: class {
    var greeting: String? { get }
    var greetingDidChange: ((GreetingViewModelProtocol) -> ())? { get set } // function to call when greeting did change
    init(person: Person)
    func showGreeting()
}

class GreetingViewModel : GreetingViewModelProtocol {
    let person: Person
    var greeting: String? {
        didSet {
            self.greetingDidChange?(self)
        }
    }
    var greetingDidChange: ((GreetingViewModelProtocol) -> ())?
    required init(person: Person) {
        self.person = person
    }
    func showGreeting() {
        self.greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
    }
}

class GreetingViewController : UIViewController {
    var viewModel: GreetingViewModelProtocol! {
        didSet {
            self.viewModel.greetingDidChange = { [unowned self] viewModel in
                self.greetingLabel.text = viewModel.greeting
            }
        }
    }
    let showGreetingButton = UIButton()
    let greetingLabel = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.showGreetingButton.addTarget(self.viewModel, action: "showGreeting", forControlEvents: .TouchUpInside)
    }
    // layout code goes here
}
// Assembling of MVVM
let model = Person(firstName: "David", lastName: "Blaine")
let viewModel = GreetingViewModel(person: model)
let view = GreetingViewController()
view.viewModel = viewModel

MVVM 패턴은 코드를 유지보수하는 데 굉장히 편리하다.
또한, ReactiveCocoa, RxSwift or PromiseKit와 같은 functional reactive programming과 함께 사용할 때 그 진가를 발휘한다.

Dependency Inversion Principle

위 MVVM 패턴의 예제에서 ViewModel은 Dependency Inversion Principle 의존성 역전 원칙에 따라 (view model) protocol 타입에 의존하도록 설계했다.

Dependency Inversion Principle은 객체 지향 원칙(SOLID) 중 하나로, 의존 관계가 역전되도록 설계함을 의미하는데, 변하기 쉬운 것보다 변하기 어려운 것에 의존하도록 설계하라는 원칙이다.
변하기 어려운 것은 추상화된 것을 의미한다(class보다는 interface, protocol, abstract).

Reference

iOS Architecture Patterns

post-custom-banner

0개의 댓글