SwiftUI 데이터 바인딩 - State

기존 프로젝트는 RxSwift로 데이터 바인딩 처리를 했는데, SwiftUI로 만들어진 View 들은 프로퍼티 래퍼(@State, @StateObject, @ObservedObject)을 통해서 데이터 바인딩을 해보려한다

State

SwiftUI가 관리하는 Property Wrapper

struct PlayButton: View {
  @State private var isPlaying: Bool = false // Create the state.

  var body: some View {
      Button(isPlaying ? "Pause" : "Play") { // Read the state.
          isPlaying.toggle() // Write the state.
      }
  }
}

isPlaying의 값이 변경될 때마다 isPlaying 의 값과 연관있는 뷰 계층을 업데이트

state는 뷰 계층의 최상위 뷰에서 private으로 선언하고, 하위 뷰에 공유

@Binding

하위 뷰에 State 공유하기

struct PlayView: View {
	@State private var isPlaying = false
	
	var body: some View {
	  PlayButton(isPlaying: isPlaying)
	    .onAppear {
	      DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
	        print("isPaying = \\(isPlaying)")
	      }
	    }
	}
}

struct PlayButton: View {
  @State var isPlaying: Bool
  
  var body: some View {
    Button(isPlaying ? "Pause" : "Play") {
      isPlaying.toggle()
    }
  }
}

위 코드처럼 하위 뷰 PlayButton에 State를 넘겨주면 하위 뷰 역시 isPlaying의 값이 바뀔 때마다 UI 상태가 업데이트 된다

하지만 하위 뷰 PlayButton에서 isPlaying의 값을 변경한다고 해서 부모뷰의 isPlaying 값이 변경되지는 않는다

struct PlayerView: View {
  @State private var isPlaying: Bool = false

  var body: some View {
      VStack {
	        // binding을 전달
          PlayButton(isPlaying: $isPlaying)
      }
  }
}

struct PlayButton: View {
  @Binding var isPlaying: Bool

  var body: some View {
      Button(isPlaying ? "Pause" : "Play") {
          isPlaying.toggle()
      }
  }
}

하위 뷰에서도 State의 값을 변경하기 위에서는 위처럼 State가 아니라 Binding을 전달하면 된다

Object로 State 관리하기

@Observable
class Library {
  var name = "My library of books"
	var location = "Near"
}

위처럼 @Observable을 사용하면 여러개의 property를 묶어서 하나의 오브젝트로 관리할 수 있다

struct ContentView: View {
  @State private var library = Library()

  var body: some View {
		// 1.
    LibraryView(library: library)
    // 2.
    LibraryView(library: library)
	    .task {
		    library = Library()
	    }
  }
}

@Observable로 정의된 오브젝트를 뷰에서 사용할 때 1번 방법처럼 사용하면 ContentView가 업데이트 될 때마다 library 오브젝트가 새로 생성되기 때문에 2번 방법처럼 task 를 사용하여, 뷰가 처음 그려질 때만 오브젝트가 생성되도로 하는 것이 효율적이다

카테고리:

수정:

댓글 남기기