상태, Observable 객체, 그리고 Environment 객체로 작업하기

2 분 소요

상태, Observable 객체, Environment 객체

  • 사용자 인터페이스의 모양과 동작을 결정하는 상태 제공
  • 사용자 인터페이스 레아아웃을 구성하는 뷰는 뷰와 바인딩된 상태 객체가 시간이 지남에 따라 변하면 그 상태에 따라 자동으로 뷰가 업데이트 됨

상태 프로퍼티

상태 프로퍼티(state property)

  • 현재 상태를 저장
  • 간단한 데이터 타입을 저장
  • @State 프로퍼티 래퍼 사용
  • private 프로퍼티로 선언
struct ContentView: View {

    @State private var wifiEnalbed = true
    @State private var userName = ""
    
    var body: some View {
.
.
}

바인딩

  • 프로퍼티 이름앞에 $ 키워드 사용
struct ContentView: View {

    @State private var wifiEnalbed = true
    @State private var userName = ""
    
    var body: some View {
        VStack {
            TextField("Enter user name", text: $userName)
            Text(userName)
        }
    }
}

상태 프로퍼티에 변화가 생길 때마다 뷰 계층구조는 SwiftUI에 의해 다시 렌더링
userName 프로퍼티에 ‘$’ 표시 없이 사용된 이유:
상태 프로퍼티에 할당된 값을 참조하였기 때문

토글 뷰 바인딩

var body: some View {
    VStack {
        Toggle(isOn: $wifiEnabled) {
            Text("Enalbe Wi-Fi")
        }
        TextField("Enter user name", text: $userName)
        Text(userName)
        Image(systemName: wifiEnalbed ? "wifi" : "wifi.slash")
    }
}

상태 바인딩

.
.
    VStack {
            Toggle(isOn: $wifiEnabled) {
                Text("Enalbe Wi-Fi")
            }
            TextField("Enter user name", text: $userName)
            WifiImageView()
        }
    }
.
.
struct WifiImageView: View {

    var body: some View {
        Image(systemName: wifiEnabled ? "wifi" : "wifi.slash") // 오류 발생
    }
}

Image 뷰는 메인 뷰의 범위 밖
-> @Binding 프로퍼티 래퍼 이용

            WifiImageView(wifiEnabled: $wifiEnabled)
        }
    }
.
.
struct WifiImageView: View {

    @Binding var wifiEnabled : Bool

    var body: some View {
        Image(systemName: wifiEnabled ? "wifi" : "wifi.slash") 
    }
}

Observable 객체

상태 프로퍼티: 하위 뷰가 아니거나 상태 바인딩이 구현되어 있지 않은 다른 뷰는 접근x (일시적)
Observable 객체: 여러 다른 뷰들이 외부에서 접근할 수 잇는 영구적인 데이터를 표현

  • ObservableObject 프로토콜을 따르는 클래스나 구조체 형태
  • 시간에 따라 변경되는 하나 이상의 데이터 값을 모으고 관리하는 역할
  • 타이머나 알림과 같은 이벤트 처리
  • 게시된 프로퍼티(published property) -> 게시자를 구독(subscribe) 자동 업데이트
  • Combine 프레임워크
    • 게시자(publisher)와 구독자(subscriber) 간의 관계 구축
    • 여러 게시자를 하나의 스트림으로 병합
    • 게시된 데이터를 구독자 요구에 맞게 변형
    • 복잡한 수준의 연쇄 데이터 처리 작업
    • 게시된 프로퍼티 구현하는 가장 쉬운 방법: @Published 프로퍼티 래퍼
        import Foundation
        import Combine
      
        class DemoData : ObservableObject {
      
            @Published var userCount = 0
            @Published var currentUser = ""
                  
            init() {
                updateData()
            }
                  
            func updateData() {}
        }
      
    • observable 객체를 구독하기 위해: @ObservedObject 프로퍼티 래퍼
        import SwiftUI
              
        struct ContentView: View {
                  
            @ObservedObject var demoData : DemoData
                  
            var body: some View {
               Text("\(demoData.currentUser), you are user number \(demoData.userCount)")
            }
        }
              
        struct ContentView_Previews: PreviewProvider {
            static var previews: some View {
                ContentView(demoData: DemoData())
            }
        }
      

      구독하게 되면 게시된 프로퍼티에 접근


Environment 객체

어떤 뷰에서 다른 뷰로 이동(navigation)할때,
이동될 뷰에서도 동일한 구독 객체 에 접근해야 한다면 구독 객체에 대한 참조체 를 전달

.
.
@ObservedObject var demoData : DemoData = DemoData()
.
.
NavigationLink(destination: SecondView(demoData)) {
    Text("Next Screen")
}

demoData 객체에 대한 참조체를 전달

여러 뷰가 동일한 구독 객체에 접근해야 하는 경우 복잡 -> Environmnet 객체

  • ObservableObject 프로토콜을 따름
  • SwiftUI 환경에 저장
  • 뷰에서 뷰로 전달할 필요없이 모든 뷰가 접근
  • @EnvironmentObject 프로퍼티 래퍼 이용
      @EnvironmentObject var demoData: DemoData
    
  • 옵저버(observer) 내에서 초기화x
      let contentView = ContentView()
    
      let demoData = DemoData() // 객체의 인스턴스 저장
    
      if let windowScene = scene as? UIWindowScene {
          let window = UIWindow(windowScene: windowScene)
          window.rootViewController = UIHostingController(rootView:
                  contentView.environmentObject(demoData))
          self.window = window
          window.makeKeyAndVisible()
      }
      .
      .
      struct ContentView_Previews: PreviewProvider {
          static var previews: some View {
    
              ContentView().environmentObject(DemoData()) // 선언부 수정
    
          }
      }
    

    구독 객체와 같은 동작, 모든 레이아웃 뷰가 접근가능

카테고리:

업데이트: