버그 잡이

SwiftUI - ObservableObject vs StateObject 본문

SwiftUI

SwiftUI - ObservableObject vs StateObject

버그잡이 2024. 6. 16. 18:53

SwiftUI는 선언형 프레임워크로서, 상태 관리를 효율적으로 할 수 있도록 다양한 도구를 제공합니다.

그 중에서도 ObservableObject와 StateObject는 데이터 모델 관리에 중요한 역할을 합니다.

이번 글에서는 ObservableObject와 StateObject의 정의와 사용법, 두 객체의 공통점과 차이점, 그리고 언제 어떻게 사용해야 할지에 대해 알아보겠습니다.

 

ObservableObject란?

ObservableObject는 SwiftUI에서 데이터의 변화를 감지하고, 뷰에 이를 반영할 수 있도록 도와주는 프로토콜입니다. 주로 뷰 모델(ViewModel)로 사용되어 데이터의 변경을 뷰에 전달합니다.

 

주요 특징:

  • 클래스 기반 객체에서 사용됩니다.
  • @Published 어노테이션을 사용하여 프로퍼티 변화를 자동으로 알립니다.
import SwiftUI
import Combine

class UserSettings: ObservableObject {
    @Published var username: String = "Guest"
}

struct ContentView: View {
    @ObservedObject var settings = UserSettings()

    var body: some View {
        VStack {
            Text("Username: \(settings.username)")
            TextField("Username", text: $settings.username)
        }
        .padding()
    }
}

 

StateObject란?

StateObject는 SwiftUI에서 객체 상태를 관리하고, 해당 객체가 뷰의 상태 변경에 따라 재생성되는 것을 방지합니다. 

이는 ObservableObject의 단점과도 연관이 되는데, ObservableObject는 뷰가 재성성시 객체가 초기화 되는 이슈가 있습니다. 아래 예제 코드에서 button 클릭시 뷰가 재생성 되면서 counter 객체도 초기화되는 겁니다. 그 결과 count가 원하는 숫자로 나오지 않는데요. StateObject는 이러한 문제를 해결하여 뷰가 재생성 되어도 객체를 유지합니다.

 

주요 특징:

  • 뷰의 초기화 시점에 한 번만 생성되며, 뷰의 재렌더링 시에도 동일한 객체가 유지됩니다.
  • 뷰 내에서 객체의 수명이 관리되는 경우에 적합합니다.
import SwiftUI

class Counter: ObservableObject {
    @Published var count: Int = 0
}

struct CounterView: View {
    @StateObject private var counter = Counter()

    var body: some View {
        VStack {
            Text("Count: \(counter.count)")
            Button("Increment") {
                counter.count += 1
            }
        }
        .padding()
    }
}

 

둘의 공통점 및 차이점

공통점

  • 둘 다 클래스 기반 객체에서 사용됩니다.
  • SwiftUI에서 데이터 변화를 뷰에 반영하도록 설계되었습니다.
  • @Published 속성으로 프로퍼티 변화를 알릴 수 있습니다.

차이점

  • 생성 및 수명 관리: ObservableObject는 외부에서 생성된 객체를 뷰에서 사용(주입)할 때 적합하며, StateObject는 뷰가 객체를 소유하고 수명을 관리할 때 사용됩니다.
  • 뷰의 재생성: ObservableObject는 뷰가 재생성될 때 객체도 다시 초기화될 수 있지만, StateObject는 뷰의 재생성에도 동일한 객체를 유지합니다.

 

언제 어떻게 써야할까?

 

ObservableObject 사용 시점

  • 외부에서 객체가 생성되고, 뷰에 주입될 때
  • 여러 뷰에서 데이터를 공유하고자 할 때
import SwiftUI

class AppSettings: ObservableObject {
    @Published var isDarkMode: Bool = false
}

struct ParentView: View {
    @StateObject var settings = AppSettings()

    var body: some View {
        VStack {
            ChildView1(settings: settings)
            ChildView2(settings: settings)
        }
    }
}

struct ChildView1: View {
    @ObservedObject var settings: AppSettings

    var body: some View {
        Toggle("Dark Mode", isOn: $settings.isDarkMode)
    }
}

struct ChildView2: View {
    @ObservedObject var settings: AppSettings

    var body: some View {
        Text("Dark Mode is \(settings.isDarkMode ? "On" : "Off")")
    }
}

 

 

StateObject 사용 시점

  • 뷰의 생명 주기 동안 상태를 유지하고 싶을때
  • 객체 주입 없이 단순하게 구현하고 싶을때
  • 뷰의 생명 주기와 함께 객체의 생명 주기를 관리하고 싶을때
import SwiftUI

class TaskManager: ObservableObject {
    @Published var tasks: [String] = []
    
    func addTask(_ task: String) {
        tasks.append(task)
    }
}

struct TaskView: View {
    @StateObject private var taskManager = TaskManager()

    var body: some View {
        VStack {
            List(taskManager.tasks, id: \.self) { task in
                Text(task)
            }
            Button("Add Task") {
                taskManager.addTask("New Task")
            }
        }
        .padding()
    }
}

 

 

 

 

 

* 참고

- https://developer.apple.com/documentation/combine/observableobject

- https://developer.apple.com/documentation/swiftui/stateobject



 

 

반응형
Comments