SwiftUI의 @ObservedObject

June·2023년 3월 3일
0

SwiftUI-Data

목록 보기
11/12
post-thumbnail

@ObservedObject

부모 뷰 - 자식 뷰 사이의 양방향 바인딩

@StateObject 데이터를 @ObservedObject를 사용해 자식 뷰와 공유한다.


@ObservedObject 사용 이유

@ObservedObject는 데이터에 대한 변경 사항을 뷰에 알리는 매우 중요한 기능을 한다.

@ObservedObject없이 데이터의 스냅샷은 얻을 수 있지만, 데이터는 더 이상 업데이트되지는 않는다.
@ObservedObject가 없다면 더 이상 객체의 변경사항을 관찰하지 않는다.

import SwiftUI

/// Weather - 모델 
struct Weather: Identifiable {
    let id = UUID()
    var day = ""
    var icon = ""
}

/// Forecast - 뷰모델
class Forecast: ObservableObject {
    @Published var forecast = [Weather]()
    
    init() {
        forecast = [
            Weather(day: "일요일", icon: "cloud.snow.fill"),
            Weather(day: "월요일", icon: "sun.min.fill"),
            Weather(day: "화요일", icon: "sun.max.fill"),
            Weather(day: "수요일", icon: "cloud.sun.fill"),
            Weather(day: "목요일", icon: "sun.min.fill"),
            Weather(day: "금요일", icon: "cloud.drizzle.fill"),
            Weather(day: "토요일", icon: "cloud.sleet.fill")
        ]
    }
    
    func fetchAnotherWeek() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [self] in
            forecast.append(contentsOf: forecast)
        }
    }
}

/// AboutObservedObject - 뷰
struct AboutObservedObject: View {
    @StateObject private var weather = Forecast()
    @State private var showForecast = false
    
    var body: some View {
        NavigationView {
            ZStack {
                VStack(spacing: 20) {
                    CommonTextView(title: "", desc: "@ObservedObject 타입의 자식뷰에 @StateObject 레퍼런스 전달")
                    
                    Text(weather.forecast[0].day)
                    
                    Image(systemName: weather.forecast[0].icon)
                        .font(.system(size: 130))
                        .foregroundColor(.yellow)
                    
                    Button("2주(14일) 날씨 조회하기") {
                        showForecast = true
                        weather.fetchAnotherWeek()
                    }
                }
                
                if showForecast {
                    ForecastView(weather: weather, showForecast: $showForecast)
                }
            }
        }
    }
}

/// ForecastView - 서브뷰
struct ForecastView: View {
    @ObservedObject var weather: Forecast
    @Binding var showForecast: Bool
    
    var body: some View {
        VStack {
            List(weather.forecast) { day in
                Label {
                    Text(day.day)
                        .font(.title)
                } icon: {
                    Image(systemName: day.icon)
                        .font(.title)
                        .foregroundColor((.yellow))
                }
            }
            
            Button("닫기") {
                showForecast.toggle()
            }
        }
    }
}

위 코드를 실행하면 AboutObservedObject뷰가 가장 먼저 보여진다.
거기서 '2주(14일) 날씨 조회하기' 버튼을 눌러보면 ForecastView로 이동하며 가장 먼저 일주일치 날씨 데이터가 보여진다. 그리고 1초 후 또 일주일치 날씨 데이터가 추가로 뜨는 것을 볼 수 있다.

여기서 중요한 것은,

ForecastView에 @ObservedObject가 없으면 ForecastView 서브뷰는 더 이상 부모의 @StateObject에 대한 변경 사항을 관찰하지 않는다는 것.
즉 @ObservedObject가 없으면 처음 일주일치 데이터만 출력되고, 1초 후에 추가로 뜨는 다음 일주일치 데이터는 출력되지 않는다는 것이다.

이렇게 @ObservedObject는 데이터의 변경 사항을 해당 뷰에 알리는 역할을 한다.


Preview에서 @ObservedObject 사용하기

struct AboutObservedObject_Previews: PreviewProvider {
    @StateObject private static var weather = Forecast()
    
    static var previews: some View {
        Group {
            AboutObservedObject()
            
            ForecastView(weather: weather, showForecast: Binding.constant(true))
//            ForecastView(weather: Forecast(), showForecast: .constant(true))
        }
    }
}
  1. @StateObject private static var weather = Forecast()
    처럼 static 속성을 사용해 객체를 @ObservedObject속성으로 전달하거나,
  2. ForecastView(weather: Forecast(), showForecast: .constant(true))
    처럼 이니셜라이저에서 객체를 직접 생성할 수도 있다.
  • 프리뷰에서 @State변수를 생성할 수 있지만, previews의 속성이 static이기 때문에 @State변수 역시도 static이어야 한다.
  • Binding.constant를 사용해 프리뷰에서 사용하고자 하는 샘플 데이터 전달이 가능하다.

ObservedObject 정리

  • 하위 뷰에 @StateObject를 전달할 때 사용
  • 부모의 @StateObject에 대한 변경사항을 관찰할 때 사용
  • 뷰를 다시 그릴 때 ObservableObject 객체 클래스를 다시 만들려고 하는 경우에 사용
  • @StateObject는 객체를 유지, @ObservedObject는 객체를 유지하지 않음

profile
안다고 착각하지 말기

0개의 댓글