안녕하세요. Narvis2 입니다.
이번 시간에는 Swift 에서 ViewModel 을 사용하여 MVVM 패턴을 사용하는 방법에 대하여 알아보도록 하겠습니다.
🍀 MVVM (Model - View - ViewModel)
Model👉Application에서 사용되는 데이터와 그 데이터를 처리하는 부분- 서버에서 들어오는 데이터, 디바이스에 저장되는 Local 데이터
View👉 사용자에게 보여지는UI부분ViewModel의 데이터가 변경된 것을 감지해UI를Update함
ViewModel👉View를 표현하기 위해 만든View를 위한ModelView와Model을 연결 시켜 주는 곳- 데이터의 변경사항을 알려주는
LiveData를 가지고 있음 Model이 변경된 것을 감지하여UI를 위한 데이터를 변경해야함
View는Model을 모르지만ViewModel을 알고 있음ViewModel은View를 모르지만Model을 알고 있음View를 통해 들어온 사용자 인터렉션은ViewModel에게 전달되어 특정 로직이 실행됨- ✅ 즉, 의존성 분리
View와Model사이의 의존성이 없음 (View의 부담을 줄여줌)ViewModel은Data Binding을 통해View와Model을 이어줌- 각각의 부분은 독립적 이기 때문에 모듈화 하여 개발할 수 있음.
- ✅ 장점
View와data가 완전 분리된다.View가data관리를 할 필요가 없으므로UI update에만 집중할 수 있음- 각
View간에data공유가 훨씬 쉬워진다. - 유지보수의 장점 👉 의존성이 분리되므로,
View의 코드를 변경할 때 다른 부분의 코드를 변경할 필요가 없음
- ✅ 동작 순서
- 1️⃣ 사용자의
action이View를 통해 들어옴 - 2️⃣
command패턴을 사용하여ViewModel에Action을 전달함 - 3️⃣
ViewModel이Model에서data를 요청하고,Model은ViewModel에서 요청받은 데이터를ViewModel에 전달함 - 4️⃣
ViewModel은 응답받은 데이터를 가공, 저장함 - 5️⃣
View는ViewModel과의Data Binding을 이용해 화면을 갱신함 (Observer 패턴)
- 1️⃣ 사용자의
🍀 Swift with ViewModel
ObservableObject를 이용하여Data Model과View를 쉽게Binding할 수 있음ObservableObject로ViewModel을 설정하고,View단에서는ViewModel에@ObservedObject를 붙여줌으로서ViewModel의 변화를 관찰 할 수 있고, 그 변화에 반응할 수 있음
☘️ @ObservableOjbect
해당 클래스의 인스턴스를 관찰하고 있다가 값이 변경되면
View를Update한다.예제 👇
1 2 3
class MainviewModel: ObservableObject { }
☘️ @Published
ObservableOject에서 속성을 선언할 때 사용 하는PropertyWrapper- 해당 속성이 업데이트 될 때마다
View를Update,$operator를 붙여 게시자에 엑세스 가능 @Published가 붙어있는 변수가 변경 되면 이를 지켜보고 있는View에게ViewModel이 변경되었음을 알려주고,View는 새로운 객체를 바탕으로View를Refresh한다.Android 의
LiveData와 유사예제 👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class MainviewModel: ObservableObject { @Published var youngjun = Person(name: "영준", birthday: Date()) var name: String { youngjun.name } var age: String { return "29" } func changeName(_ name: String) { youngjun.name = name } }
☘️ @ObservedObject
ObservableObject를구독하고 값이Update될 때 마다View를 갱신하는PropertyWrapperView를 만료시키고 새로 그림⚠️
View가 새로 그려질 때 마다인스턴스가 새로 초기회됨예제 👇
1 2 3
struct ContentView: View { @ObservedObject var viewModel = MainViewModel() }
☘️ @StateObject
- 단 한 번 인스턴스가 생성
View를 처음부터 새로 그리지 않고,ObservableObject에서의 데이터가 변할 때, 그ObservableObject의 데이터가 들어간 부분만View를 다시 그 림View가 얼마나 다시 그려지든 상관없이 별개의 객체로 관리예제 👇
1 2 3
struct ContentView: View { @StateObject var viewModel = MainViewModel() }
☘️ SharedViewModel 구현
- ✅ 추천
Observable Object를 처음 초기화 할 때는StateObject를 사용하고, 이미 객체화된 것을 넘겨 받을 때는ObservedObject를 사용
StateObject와ObservedObject를 사용하여SharedViewModel을 사용가능상위
View에서 객체로 만들어서 따로 저장해두고, 하위View도 이Observable Object의 변화를 감지하고, 같은 정보에 접근 할 수 있도록 할 수 있음예제 👇
1 2 3 4 5 6 7 8 9 10 11 12 13
struct UpperView: View { @StateObject var viewModel: MainViewModel = MainViewModel() var body: some View { LowerView(viewModel: viewModel) } } struct LowerView: View { @ObservedObject var viewModel: ViewModel var body: some View { Text("Hello") } }
☘️ @State
DataBinding을 위해 사용$키워드를 붙혀DataBinding$가 붙으면 값을 수정가능한Binding타입 참조
@State는View외부로는 사용할 수가 없고private형태로 내부에서만 사용예제 👇
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
struct ContentView: View { @State var isToggleOn: Bool = true var body: some View { VStrck { Toggle(isOn: $isToggleOn) { Text("글자를 가립니다.") }.padding() if isToggleOn { Text("그으으을자!") } } } }
☘️ @Binding
2개의
View가 동시에 하나의State를 참조 해야하는 경우 사용예제 👇
1 2 3 4 5 6 7
struct Toggole: View { @Binding var isOn: Bool var body: some View { // TODO.. } }