Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- HIG
- MVVM
- 리팩토링
- Xcode
- uitableview
- collectionview
- 리펙터링
- 클린 코드
- tableView
- 리펙토링
- swiftUI
- rxswift
- Observable
- UICollectionView
- combine
- Protocol
- swift documentation
- clean architecture
- Refactoring
- UITextView
- Clean Code
- uiscrollview
- RxCocoa
- ribs
- SWIFT
- 애니메이션
- Human interface guide
- ios
- map
- 스위프트
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - SwiftUI] @ObservedObject, @StateObject 개념, 차이점, 사용 방법 (MVVM 패턴) 본문
iOS 기본 (SwiftUI)
[iOS - SwiftUI] @ObservedObject, @StateObject 개념, 차이점, 사용 방법 (MVVM 패턴)
jake-kim 2022. 10. 28. 23:26
* @Published, @objecervableObject 개념은 Combine이므로, Combine 관련 이전 포스팅 글 참고
@ObservedObejct 란?
- observable 객체를 구독하는 property wrapper
- observable 객체가 변경되면 뷰에 업데이트 시켜주는 기능
- 내부 코드
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper @frozen public struct ObservedObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject {
@dynamicMemberLookup @frozen public struct Wrapper {
public subscript<Subject>(dynamicMember keyPath: ReferenceWritableKeyPath<ObjectType, Subject>) -> Binding<Subject> { get }
}
public init(initialValue: ObjectType)
public init(wrappedValue: ObjectType)
public var wrappedValue: ObjectType
public var projectedValue: ObservedObject<ObjectType>.Wrapper { get }
}
- @ObservedObject 사용 방법
- ObservableObject를 준수하는 모델을 만들고, 그 모델에서 값이 변경되면 뷰에 반영하기 위함
- ObservableObejct를 준수하는 인스턴스를 참조하기 위해서 @ObservedObject로 선언하여 참조
ex) @ObservedObject 사용하여 MVVM 패턴 만들기
- 모델 정의 (ObservableObject를 준수)
- ObservableObject는 class 형태만 가능하므로 struct가 아님을 주의
- @Published는 이전 포스팅 글 Combine 참고
final class MyViewModel: ObservableObject {
@Published var isOn = false
func toggle() {
isOn.toggle()
}
}
- 위 모델의 인스턴스를 @ObservedObject로 참조
struct ContentView: View {
@ObservedObject var viewModel1 = MyViewModel()
var body: some View {
VStack {
Button(viewModel1.isOn ? "on" : "off") {
viewModel1.toggle()
}
}
}
}
@StateObject
- SwiftUI는 상태가 변경되면 뷰를 처음부터 다시 만들어서 그리는 동작이 있지만, @StateObject를 사용하면 뷰를 다시 만들지 않고 항상 동일한 뷰가 사용
- 내부 코드
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
@frozen @propertyWrapper public struct StateObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject {
@inlinable public init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType)
public var wrappedValue: ObjectType { get }
public var projectedValue: ObservedObject<ObjectType>.Wrapper { get }
}
ex) @StateObject 사용 방법
- @ObservedObject와 동일하게 ObservableObject를 만들고, 그 인스턴스를 @StateObject로 만들어서 사용
struct ContentView: View {
// @ObservedObject var viewModel1 = MyViewModel()
@StateObject var viewModel2 = MyViewModel()
var body: some View {
VStack {
Button(viewModel2.isOn ? "on" : "off") {
viewModel2.toggle()
}
}
}
}
final class MyViewModel: ObservableObject {
@Published var isOn = false
func toggle() {
isOn.toggle()
}
}
@ObjervedObject와 @StateObject 차이점
- 둘 다 ObservableObject를 구독하여, 이 값이 변경되면 뷰에 반영해주는 property wrapper 형태
- 상태 변경이 있을땐 @ObjervedObject는 뷰를 다시 생성해서 그리지만, @StateObject는 뷰를 다시 생성하지 않고 항상 동일한 뷰가 사용 (효율)
- 기본적으로 @StateObject를 사용하되, 해당 프로퍼티를 subview에게도 주입시켜야 한다면, @ObservedObject로 선언하여 사용할것
- subview에 @StateObject 프로퍼티를 주입하면, 해당 @StateObject의 수명 주기가 두 곳에서 관리가 되므로 의존성을 줄이기 위해 @ObservedObejct를 사용
@ObservedObject와 @StateObject 차이 코드로 이해하기
ex) 부모 뷰에서 상태값이 업데이트 되어 뷰가 다시 그려질때, ObservableObject를 구독하고 있는 subview의 상태값이 초기화 되는지 유무를 테스트
- 모델 준비
final class MyViewModel: ObservableObject {
@Published var isOn = false
func toggle() {
isOn.toggle()
}
}
- ObservedObject로 구독하고 있는 뷰 준비
struct MyView: View {
@ObservedObject var viewModel = MyViewModel()
var body: some View {
Button(viewModel.isOn ? "on" : "off") {
viewModel.toggle()
}
}
}
- 부모 뷰안에 위 뷰를 넣어서, 부모 뷰가 다시 그려지는 상황 준비
struct ContentView: View {
@State var isOn = false
var body: some View {
VStack {
Button(isOn ? "on" : "off") {
isOn.toggle()
}
Divider()
MyView()
}
}
}
- @ObservedObject로 선언하면 뷰가 다시 생성되어, 상태값들이 초기화 되는 것을 확인
- 위에있는 on/off 버튼의 상태만 변경되어야 하는데, @ObservedObject로 선언한 subview의 상태값이 초기화 되면서 off로 변경
- @StateObject로 선언하면 뷰가 다시 생성되지 않아서, 상태값들이 초기화 되지 않는 것을 확인
- @ObservedObject를 @StateObject로 변경 후 실행
- 뷰가 다시 그려져도 @StateObject로 상태를 구독하고 있기 때문에 뷰가 다시 생성되지 않아서 상태가 초기화 되지 않음
struct MyView: View {
// @ObservedObject var viewModel = MyViewModel()
@StateObject var viewModel = MyViewModel()
var body: some View {
Button(viewModel.isOn ? "on" : "off") {
viewModel.toggle()
}
}
}
* 전체 코드: https://github.com/JK0369/ExObservedObject-SwiftUI
* 참고
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
https://developer.apple.com/documentation/swiftui/stateobject
https://developer.apple.com/documentation/swiftui/observedobject
https://www.avanderlee.com/swiftui/stateobject-observedobject-differences/
'iOS 기본 (SwiftUI)' 카테고리의 다른 글
Comments