ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

728x90
๋ฐ˜์‘ํ˜•

์˜ค๋Š˜์€, ์ด์ „์— ํฌ์ŠคํŒ… ํ•œ ๊ธ€์— ์ด์–ด์„œ MVVM ํŒจํ„ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์•ž์„œ ์•Œ์•„๋ดค๋˜ MVCํŒจํ„ด๊ณผ ์–ด๋–ค์ฐจ์ด๊ฐ€ ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋ฉฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

โ€ป  ๊ธ€ ์ž‘์„ฑ์‹œ ์ž˜๋ชป ๋œ ๋‚ด์šฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ, ์ž˜๋ชป๋œ ๋‚ด์šฉ ์ง€์ ํ•ด์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.!!

 

 

 


MVVM

MVVMํŒจํ„ด์€ ์•„์ฃผ ํ›Œ๋ฅญํ•œ ๋””์ž์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

Model๊ณผ View๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ด๋ฏธ ์•Œ๊ณ ์žˆ๋Š” component์ธ๋ฐ, MVC์™€ ๋‹ค๋ฅด๊ฒŒ 

 

View Model๋ผ๋Š” ์ƒˆ๋กœ์šด ์ค‘์žฌ์ž๊ฐ€ ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค.

 

(์‚ฌ์‹ค MVVM๊ณผ Apple's MVC ์‚ฌ์—์ด ์žˆ๋Š” MVP๋ชจ๋ธ์„ ์ž์ฃผ ๋น„๊ตํ•˜๊ณ ๋Š” ํ•˜์ง€๋งŒ, ์šฐ๋ฆฌ๋Š” ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.)

 

๋˜ํ•œ, ์ด๋ฏธ ์•Œ๊ณ ์žˆ๋Š” Model๊ณผ View์˜ ์—ญํ• ๋„ ์กฐ๊ธˆ ๋ฐ”๋€Œ๊ฒŒ ๋˜๋Š”๋ฐ, ์ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

 

1. Model

 

- Model์€ ๋ฐ์ดํ„ฐ, ๋„คํŠธ์›Œํฌ ๋กœ์ง, ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ๋“ฑ์„ ๋‹ด์Šต๋‹ˆ๋‹ค.

- View์™€ ViewModel์˜ ๊ตฌ์„ฑ๊ณผ ๋ณ€๊ฒฝ์—๋Š” ์ „ํ˜€ ๊ด€์—ฌํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๊ฐ€์ง€๊ณ  ์žˆ์„ Data๋งŒ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

(์‚ฌ์‹ค ๊ธฐ์กด์˜ MVC์—์„œ์˜ Model๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฅผ๊ฒŒ ์—†๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

 

 

2. View

 

- ์‚ฌ์šฉ์ž๊ฐ€ App์„ ์‚ฌ์šฉ ํ•  ๋•Œ, ์‹ค์ œ๋กœ ํ™”๋ฉด์—์„œ ๋ณด์ด๋Š” (UI)์— ๋Œ€ํ•œ layout, dataํ‘œ์‹œ๋“ฑ์„ ๋‹ด๋‹นํ•œ๋‹ค.

- Model๊ณผ๋Š” ์ง์ ‘์ ์ธ ์—ฐ๊ฒฐ์ด ์ด๋ฃจ์–ด์ ธ์„œ๋Š” ์•ˆ๋œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  MVC์™€ MVVM์˜ ์ฐจ์ด์  ์ค‘ ํ•˜๋‚˜์ธ, 

- View๋Š” ViewModel์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋ณธ์ธ์ด ์ง์ ‘ View๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค.

 

์ด๋ฅผ ์œ„ํ•ด View๋Š” ViewModel์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ๋˜๊ณ , ์‚ฌ์šฉ์ž์˜ interaction์„ ๊ฐ์ง€ํ•ด์„œ

์ด์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ViewModel์— ์š”์ฒญํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

 

3. ViewModel

 

- View์—์„œ ์ „๋‹ฌ๋ฐ›๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋กœ์ง์„ ๊ฐ–๋Š”๋‹ค.

- Model์— ๋ณ€ํ™”๊ฐ€ ์ƒ๊ธฐ๋ฉด ViewModel์ด View์—๊ฒŒ ์•Œ๋ ค์ค€๋‹ค

  • ๋ฐ์ดํ„ฐ์˜ ๋ณ€ํ™”๋ฅผ View์—๊ฒŒ ์•Œ๋ ค์ค€๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค

- ์ด์ฒ˜๋Ÿผ View์™€ Model์‚ฌ์ด์˜ ์ค‘์žฌ์ž ์—ญํ• ์„ ํ•˜๋ฉฐ, Model์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ View๊ฐ€ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ

์žฌ ๊ฐ€๊ณตํ•˜์—ฌ ์ œ๊ณตํ•ด์ฃผ๋Š” Presentaion Logic์„ ๊ฐ–์Šต๋‹ˆ๋‹ค.

 

 


 

 

์œ„์—์„œ ์„ค๋ช…ํ•œ ํ๋ฆ„์„ ํ•˜๋‚˜์˜ ๋™์ž‘์œผ๋กœ ์ƒ๊ฐํ•ด๋ณด๋ฉด,

 

1) View์—์„œ event๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

(ex ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ tapํ•จ)

2) View๊ฐ€ ํ•ด๋‹น ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ViewModel์— ์•Œ๋ ค์คŒ.

(ex View์— ํ•ด๋‹นํ•˜๋Š” VC์—์„œ ViewModel์˜ ํŠน์ • ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅ (๊ผญ ์ด๋ ‡๊ฒŒ ์•ˆ ํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค!))

3) ๋ณ€๊ฒฝ ๋œ Data๋ฅผ ํ†ตํ•ด Model์„ ์ƒˆ๋กœ ์—…๋ฐ์ดํŠธ ํ•œ๋‹ค.

4) Model์ด ๋ณ€๊ฒฝ๋˜๋ฉด ํ•ด๋‹น Model์„ ์†Œ์œ ํ•˜๊ณ  ์žˆ๋Š” ViewModel์ด ์•Œ๊ฒŒ๋œ๋‹ค.

5) ๋˜ํ•œ, ํ•ด๋‹น ViewModel๊ณผ bind๋˜์–ด์žˆ๋Š” View๊ฐ€ ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.

(View๊ฐ€ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์Šค์Šค๋กœ UI๋ฅผ ์—…๋ฐ์ดํŠธ ์ง„ํ–‰ํ•จ)

 

๋”๋ณด๊ธฐ

์ •๋ฆฌํ•ด๋ณด๋ฉด, Apples'MVC๋Š” ViewController๊ฐ€ View๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋กœ์ง์„ ๊ฐ–๊ณ  ์žˆ๋Š” ๋™์‹œ์— LifeCycle์„ ๊ด€๋ฆฌํ•˜๋Š” ๋“ฑ

Massive ํ•  ๋ฟ ์•„๋‹ˆ๋ผ, View์™€ ์ƒ๋‹นํžˆ ๋ฐ€์ ‘ํ•œ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ, MVVM์€ ViewModel์„ View๋ฅผ ์•Œ ์ง€ ๋ชปํ•˜๊ณ  , View๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋กœ์ง์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

์ด๋ฅผ ํ†ตํ•ด, ๊ฐ View ViewModel Model์ด ๋”์šฑ ๋…๋ฆฝ์ ์œผ๋กœ ์‚ฌ์šฉ์ด ๋˜๊ณ  

์œ ๋‹›๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ์ƒ๋‹นํžˆ ์šฉ์ดํ•œ ์ธก๋ฉด์ด ์žˆ์Šต๋‹ˆ๋‹ค!

 

 


 

 

MVVM ์˜ˆ์ œ ์ฝ”๋“œ

 

์ด๋ก ์ ์œผ๋กœ๋Š” ์ด๋ ‡๋‹ค๋Š”๋ฐ, ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด์„œ ํ•œ๋ฒˆ ํ™•์ธ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

(ํ•ด๋‹น ์˜ˆ์ œ๋Š” Reactive๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ž‘์„ฑํ•œ ์˜ˆ์ œ ์ฝ”๋“œ ์ž…๋‹ˆ๋‹ค. Rx๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ๋Š” ์ด ๊ณณ์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”!)

ํ•ด๋‹น ์˜ˆ์ œ ์ฝ”๋“œ๋Š” ์•ŒํŒŒ์นด๋‹˜์˜ ๋ธ”๋กœ๊ทธ์—์„œ ์ฐธ๊ณ ํ•˜์˜€์Šต๋‹ˆ๋‹ค!

 

2๊ฐœ์˜ TextField์— ์‚ฌ๋žŒ์˜ ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ๋„ฃ์œผ๋ฉด Label์— ํ‘œ์‹œ๋˜๋Š” ์•ฑ์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์šฐ์„ , Model์„ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

struct Person {
    var name: String
    var age: Int
}

์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ๊ฐ–๋Š” Person ๊ตฌ์กฐ์ฒด ์ž…๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ, Person์„ ํ‘œ์‹œ ํ•  ViewModel์„ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

 

ViewModel

struct PersonViewModel {
    var person: Person
}

 

ViewContoller์—๋Š” UITextFieldDelegate์˜ ๋ฉ”์„œ๋“œ์ธ [textFieldDidEndEditing]์„ ํ†ตํ•ด์„œ

textField์— ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚˜๋ฉด Lable์— ๋ฟŒ๋ ค์ฃผ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

extension ViewController: UITextFieldDelegate {
    func textFieldDidEndEditing(_ textField: UITextField) {
        guard let nameText = nameTextField.text,
            let ageText = ageTextField.text,
            let age = Int(ageText) else { return }
        
        personViewModel.person.name = nameText
        personViewModel.person.age = age
        
        yearLabel.text = nameText + " " + "\(age)์„ธ"
    }
}

์ด ์ƒํƒœ์—์„œ ๋ณด๋ฉด, [UI์˜ ๋ณ€ํ™” -> ViewModel์— ์˜ํ–ฅ]์˜ ๊ณผ์ •์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰ ๋‹จ๋ฐฉํ–ฅ์œผ๋กœ ์˜์‚ฌ์†Œํ†ต์„ ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๋ณด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์„, Property Observer๋ฅผ ํ†ตํ•ด DataBinding์„ ํ•˜์—ฌ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ๋ณ€๊ฒฝ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋จผ์ €, didSet์„ ํ†ตํ•ด Model์˜ Person์˜ ๋ณ€ํ™”๊ฐ€ ๊ฐ์ง€๋˜๋ฉด ๋ณ€ํ™”๋œ Data๋ฅผ Setํ•ด์ค๋‹ˆ๋‹ค.

๋˜ํ•œ, Data๋ณ€๊ฒฝ์˜ Event๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ, ์ ์ ˆํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•œ๋ฐ Closure๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

bind(lisenter: Listener?) ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ์™ธ๋ถ€์—์„œ PersonViewModel์˜ Listenerํƒ€์ž…์˜ listner๋ฅผ 

์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

 

ViewModel + DataBinding

struct PersonViewModel {
    typealias Listener = (Person) -> Void
    var listener: Listener?
    
    var person: Person {
        didSet {
            listener?(person)
        }
    }
    ...
    mutating func bind(listener: Listener?) {
        self.listener = listener
    }
}

 

์ด๋ ‡๊ฒŒ ๋œ๋‹ค๋ฉด, ViewController์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐ”์ธ๋”ฉ์„ ์ง„ํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค!

override func viewDidLoad() {
    ...
    personViewModel.bind { [weak self] person in
        self?.yearLabel.text = person.name + " " + "\(person.age)์„ธ"
    }
}

 

์ด๋ฅผ ํ†ตํ•ด์„œ textFieldDidEndEditing์—์„œ Person์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ, ์ฆ‰ ViewModel์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ

์ž๋™์œผ๋กœ yearLabel์ด ์—…๋ฐ์ดํŠธ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

์ด ๋ฟ๋งŒ textField์ž์ฒด์˜ delegate๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  DataBinding์„ ํ†ตํ•ด ๋กœ์ง์„ ์ง์ ‘ ๋งŒ๋“ค์–ด์„œ ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 


 

 

์ด๋ ‡๊ฒŒ MVVM์— ๋Œ€ํ•ด MVC์™€ ๋น„๊ตํ•˜๊ณ , ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ ์ฝ”๋“œ๋กœ ์ ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ดค์Šต๋‹ˆ๋‹ค.

MVVM์˜ ์žฅ์ ์€ ์•„์ฃผ ๋‹ค์–‘ํ•œ๋ฐ, ๋ช‡ ๊ฐ€์ง€๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž๋ฉด

1) ViewController๊ฐ€ ๊ฐ€๋ฒผ์›Œ ์ง€๊ฑฐ๋‚˜

2) View๋‚˜ ViewModel์ด ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ์— ์šฉ์ดํ•˜๋‹ค๋Š” ์  ๋“ฑ์ด ์žˆ๊ฒ ์ฃ .

 

ํ•˜์ง€๋งŒ ์ด๋Ÿฐ MVVM์—๋„ ํ•œ๊ณ„์ ์€ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.

๋”๋ณด๊ธฐ

1) ๊ฐ„๋‹จํ•œ ํ”„๋กœ์ ํŠธ์— ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” MVVM์ด ๊ณผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(๋ฐ”์ธ๋”ฉ, ์˜์กด์„ฑ ์ฃผ์ž…๊ณผ ๊ฐ™์€ ์—ฌ๋Ÿฌ ์ž‘์—…์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค.)

2) ๋ฐ”์ธ๋”ฉ์— ๋Œ€ํ•œ tool์ด ์—†์œผ๋ฉด ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๊ฐ€ ๋‹ค๋Ÿ‰์œผ๋กœ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

3) presentationLogic์ด ๋Š˜์–ด๋‚˜๋ฉด ViewModel์ด ๋น„๋Œ€ํ•ด์ง‘๋‹ˆ๋‹ค.

(์ด๊ฑด ๋ชจ๋“  ๋””์ž์ธ ํŒจํ„ด์ด ๋‹ค ๊ทธ๋Ÿด ๋“ฏ)

4) Data Binding์„ ๊ตฌํ˜„ํ•  ๋•Œ, delegate pattern, closure๋“ฑ ์ƒ๋‹นํžˆ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์ด์žˆ๋‹ค๋ณด๋‹ˆ, ์‚ฌ๋žŒ๋งˆ๋‹ค MVVM์„

๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์‹์ด ๋‹ค ๋‹ค๋ฅด๋‹ค

(MVVM์„ ์ฒ˜์Œ ์ ‘ํ•˜๋Š” ์‚ฌ๋žŒ์€ ๋ง‰๋ง‰ํ•˜๋‹ค)

 

 

 

์ด๋ ‡๊ฒŒ MVVM์— ๋Œ€ํ•œ ์ •๋ฆฌ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์ด์ƒ์œผ๋กœ ๊ธ€์„ ๋งˆ์น˜๊ณ , ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

 

 

 

 

 

 

 

 

[์ฐธ๊ณ  ์ž๋ฃŒ]

https://velog.io/@ictechgy/MVVM-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4

https://okanghoon.medium.com/rxswift-4-mvvm-with-rxswift-17a9b6d43746

https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52

 

728x90
๋ฐ˜์‘ํ˜•
๋Œ“๊ธ€
๋ฐ˜์‘ํ˜•
๋งํฌ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
Total
Today
Yesterday