관리 메뉴

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

[iOS - swift] MVC, MVP, MVVM 디자인 패턴 본문

Git, CocoaPods, Xcode, Shell

[iOS - swift] MVC, MVP, MVVM 디자인 패턴

jake-kim 2020. 5. 4. 21:23

1. MVC

1) 개념

MVC

MVC는 Model, View, Controller 세 가지 중점

 -> Controller에 많은 부하가 가게되어 해결할 방법 모색(MVP와 MVVM)

※주의할 점 : apple의 설명은 view와 controller는 밀접하게 붙어있는 개념 (view controller 하나로 취급)

 

2) MVC구현 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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;
 
 

2. MVP

1) 개념

MVP

*presenter : 증여자

 

MVC는 View와 Model사이의 의존성이 존재했지만 MVP에서는 의존성을 제거

presenter는 Model로 부터 데이터를 받는 역할을 대신 실천, 또한 view controller의 생명주기에 관여하지 않음

presenter는 view에 쉽게 접근 가능

 

단순히 Controller의 부하만 떨어뜨린것이 아닌 "테스트 용이성"의 장점도 탄생

 

2) MVP구현 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import UIKit
 
struct Person { // Model
    let firstName: String
    let lastName: String
}
 
protocol GreetingView: class {
    func setGreeting(greeting: String)
}
 
protocol GreetingViewPresenter {
    init(view: GreetingView, person: Person)
    func showGreeting()
}
 
class GreetingPresenter : GreetingViewPresenter {
    unowned let view: GreetingView
    let person: Person
    required init(view: GreetingView, person: Person) {
        self.view = view
        self.person = person
    }
    func showGreeting() {
        let greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
        self.view.setGreeting(greeting)
    }
}
 
class GreetingViewController : UIViewController, GreetingView {
    var presenter: GreetingViewPresenter!
    let showGreetingButton = UIButton()
    let greetingLabel = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside)
    }
    
    func didTapButton(button: UIButton) {
        self.presenter.showGreeting()
    }
    
    func setGreeting(greeting: String) {
        self.greetingLabel.text = greeting
    }
    
    // layout code goes here
}
// Assembling of MVP
let model = Person(firstName: "David", lastName: "Blaine")
let view = GreetingViewController()
let presenter = GreetingPresenter(view: view, person: model)
view.presenter = presenter
 
 

3.MVVM

MVVM

* 아이디어 : 중재자(View Model)는 View에 대한 정보에 신경쓰지 말고(의존성 낮춤), 데이터 바인딩*을 통해 구현

 - View Model의 실체 : View자체에 데이터 요소까지 같이 존재

                                     ex) UITableView에서는 table(View)이 존재하는 동시에 제목, 서브제목,, 등의 데이터(Model)가 존재

 

1) 개념

View속에 Controller가 내제되어 있으며, View Model은 View에 대한 데이터 정보를 모르고(뷰 자체 안에서 처리) 데이터 바인딩* 실현(contorller에 대한 부하 감소)

 

MVC에서는 Controller에 많은 부하를 주었기 때문에 View쪽으로 Controller를 보내고 비어있는 Controller자리에 중재역할을 할 View Model 개념을 삽입한 것 뿐

 

MVP는 Presenter가 View의 정보를 알고 update하지만, MVVM에서는 View Model이 View의 정보를 모름

 - View와 View Model은 1대 n 관계

 

* 데이터 바인딩(binding) : View와 View Model 사이의 양방향 데이터 흐름 (옵저버 프로퍼티의 didSet과 같은 것이 바인딩의 예 -단방향 바인딩)

 

2) 소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
 
 

* 참고한 내용의 출처 : https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52

Comments