• 카테고리

    질문 & 답변
  • 세부 분야

    모바일 앱 개발

  • 해결 여부

    미해결

GalleryView 작성시, @State? @Bidnable? 의 차이점이 뭔지 궁금합니다.

24.06.18 12:37 작성 24.06.18 12:38 수정 조회수 71

0

IOS17로 업데이트 됨에 따라,

@Observable 매크로를 활용하여 ViewModel을 활용하면,

상태 변화를 감지하여 'View에서 자동적으로 업데이트 된다.'라고 알고 있습니다.

 

@Observable 매크로를 사용해서 코드를 업데이트하던 중 궁금증이 생겨 질문을 남겨봅니다.

 

  1. ContentView, VideoView에서 AnimalViewModel의 인스턴스를 갖고 있을 때, var로 정의했을 때와 let으로 정의를 했을 때의 차이점이 있을까요?

struct ContentView: View {

    // let이나 var이나 상관없는가?
    let vm: AnimalViewModel
    var body: some View {

        NavigationStack{

            List{
            // 1. Cover Image - hero Image
                CoverImageView(vm: vm)

관련내용을 공부하다보니, 해당 링크에서

https://www.donnywals.com/comparing-observable-to-observableobjects/

"Defining an @Observable as a let property" 부분에

HomeView에서 ViewModel에 @State 프로퍼티 래퍼를 사용한 후 let을 사용한다? 라는 내용을 본적이 있습니다.

 

 

  1. GalleryView에서 @State 프로퍼티 래퍼와 @Bindable 프로퍼티 래퍼를 사용했을 때의 차이점이 뭘까요 ㅠㅠ .

     

     

    우선, @State로 했을 때는 변화의 감지를 HomeView에서도 GalleryView에서도 잘 작동하여, 슬라이더를 변화시켰을 때 Grid의 개수가 바뀝니다.

     

     

    하지만 @Bindable 프로퍼티 래퍼를 사용했을 때에는 GalleryView에서만 슬라이더 변화를 감지 하고, HomeView에서는 변화를 감지하지 못하는 상황이 벌어집니다.

     

     

    @State var vm: AnimalViewModel
    @Bindable var vm: AnimalViewModel
struct GallaryView: View {
    
    @State var vm: AnimalViewModel
    
    var body: some View {
        NavigationStack{
            ScrollView(.vertical, showsIndicators: false){
                VStack(spacing: 30){
                    
                    // 1. Image
                    Image(vm.selectedAnimal)
                        .resizable()
                        .scaledToFill()
                        .frame(width: 250, height: 250)
                        .clipShape(Circle())
                        .overlay(Circle().stroke(Color.accentColor, lineWidth: 5))
                    
                    // 2. Slider
                    Slider(value: $vm.gridColumn, in: 2...4, step: 1)
                        .padding(0)
                        .onChange(of: vm.gridColumn) {
                            withAnimation(Animation.easeInOut(duration: 1.0)){
                                vm.gridSwitch()
                            }
                        }
                    
                    // 3. Grid
                    LazyVGrid(columns: vm.gridLayout, spacing: 20){
                        ForEach(vm.animals){ animal in
                            Image(animal.image)
                                .resizable()
                                .scaledToFill()
                                .frame(width: 80, height: 80)
                                .clipShape(Circle())
                                .overlay(Circle().stroke(Color.white, lineWidth: 1))
                                .onTapGesture {
                                    withAnimation(Animation.spring()){
                                        vm.selectedAnimal = animal.image
                                    }
                                }
                        }
                    }
                    
                }  //:VSTACK
                .padding()
            } //:SCROLL
            .navigationTitle("갤러리")
            .navigationBarTitleDisplayMode(.inline)
        }  //:NAVIGATION
    }
}

 

    추가로,

@Observable 매크로를 이용한 예시가 잘 정리되어 있는 문서들이 있을까요?? 제가 잘 이해를 못한 건지, 이 부분이 너무 어렵네요.

 

감사합니다 😀

답변 2

·

답변을 작성해보세요.

1

안녕하세요 ycc3819 님

제가 확인이 늦어 이제 답변드리네요 죄송합니다.

  1. 질문주신 부분과 링크에서 나타난 것은
    @State와 @Observable을 함께 사용할 때 주의할 점은 다음과 같습니다:

     

    @State와 @Observable 사용 시점: @Observable 인스턴스를 생성하는 뷰만 @State를 사용합니다. 다른 뷰에서는 let으로 선언하여 사용합니다.

     

    @Observable을 let으로 선언: 다른 뷰에서 @Observable 인스턴스를 받을 때는 let으로 선언해도 안전합니다. 인스턴스를 소유하는 뷰는 @State를 사용해야 합니다.

     

    이 원칙을 따르면 뷰의 상태 관리와 데이터 흐름이 명확해집니다.
    그렇기 때문에 최소 뷰의 소유권을 가지고 있는 최상위에서는 @State 을 사용하고, 그것을 인스턴스 받어서 사용할때는 let 을 사용하게 이론적으로 안전합니다. 하지만, var 을 사용해도 error 가 발생되거나 그러진 않지만 safe code 을 위해서는 let 사용이 권장되는것입니다.

  2. @State 는 처음 instance 생성할때 viewModel 을 선언할때 사용되며 @Bindable 은 선언된 ViewModel 을 binding 하는 역활을 합니다. 자세한 사항은 iOS17 강의에서 Observation 부분을 참고하시면 됩니다. Project 에서 @Observable 을 사용해서 변환하는것도한 코드 변환 하고 확인 후에 강의및 예제 코드도 조만간 업데이트 하겠습니다.

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2024.06.20

안녕하세요, 인프런 AI 인턴입니다.

SwiftUI에서 @State@Bindable (실제로는 @Binding)의 개념은 데이터의 소유권과 데이터를 어떻게 다루는지에 따라 다릅니다.

  1. @State는 SwiftUI의 View 내부에서 사용되며, View의 상태를 관리하는 데 사용됩니다. 이렇게 선언된 변수는 View가 소유하며, 해당 변수의 값이 변경되면 View는 자동으로 업데이트 됩니다. @State 변수는 주로 View 내에서 private하게 사용되며, 자신이 직접 변경할 수 있는 상태를 다룰 때 사용됩니다.

  2. @Binding은 부모 View로부터 전달받은 데이터를 참조하며, 이 데이터의 변경 사항을 부모 View에도 반영하고 싶을 때 사용됩니다. 즉, @State를 사용하여 부모 View에서 관리되는 상태를 자식 View로 전달하고 싶을 때, @State 변수를 @Binding 변수로 변환하여 자식 View로 전달합니다. 이를 통해 자식 View에서 변경된 내용이 부모 View로 전파되어 상태가 동기화됩니다.

GalleryView와 HomeView 사이에서 발생하는 상황을 보면, @State를 사용한 경우 GalleryView에서 상태 변경이 잘 감지되는 것은 해당 View가 직접 상태를 소유하고 있기 때문입니다. 반면, @Bindable(@Binding이 맞는 표현)을 사용하면, GalleryView는 상태의 변화를 감지할 수 있지만, 이 변화가 HomeView로 전파되려면 HomeView 또한 이 상태를 관리하고 있어야 하며, GalleryView에 이 상태를 @Binding을 통해 전달해야 합니다.

ContentView, VideoView에서 AnimalViewModel의 인스턴스를 let으로 정의했을 때와 var으로 정의했을 때의 차이점에 관한 질문에 대해서는, SwiftUI의 View는 불변(immutable)이라는 특성을 가지고 있기 때문에, @Observable 객체를 let으로 선언하여도 상태 변화를 감지할 수 있습니다. letvar 사이에서의 주요 차이점은 해당 변수의 재할당 가능성에서 나옵니다. @ObservableObject를 사용하는 경우, 객체의 속성이 변경되더라도 객체 자체의 할당을 변경할 필요는 없으므로, let으로 선언하여도 충분합니다.

마지막으로, @Observable에 대한 예시가 잘 정리된 문서를 찾으시는 것 같은데, @ObservableObject 태그와 관련하여 많은 사례와 정보가 공식 Apple 문서SwiftUI 튜토리얼 등에서 찾아볼 수 있습니다. 특히, Apple의 공식 문서와 튜토리얼은 기본적인 사용법부터 심화된 예시까지 잘 설명하고 있어 도움이 될 수 있습니다.

님이 찾으시는 내용과 직접적으로 연관된 자료는 제공한 정보에 포함되어 있지 않으므로, 직접 참고할 수 있는 링크 또는 구체적인 예시 제공은 어렵습니다만, 기본적인 개념 설명으로 도움이 되었기를 바랍니다.

채널톡 아이콘