ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SwiftUI) State, Binding wrapper
    SwiftUI/Basic Property Wrappers 2021. 9. 13. 17:02

    SwiftUI 로 개발을 하다보면 다음과 같은 Property Wrapper 가 아주 많이 보이게 되는데, 

    이번 포스트에서는 매우매우 빈번히 쓰이는 wrapper 중에서 @State, @Bind 대해서 알아보도록 하겠습니다. 

     

     


     

     

    @State

     

    SwiftUI 에서 View 들은 Struct 이고, Struct 는 value type 으로,  값을 바꾸는게 허용되지 않아요 ..

    SwiftUI 에서는 값들을 바꿀 수 있게 해주기 위해 @State property Wrapper 를 제공합니다. 

    struct ContentView: View {
        var testString = ""
        var body: some View {
            
            Button(action: {
    //            testString = "asd"    Cannot assign to property: 'self' is immutable
            }, label: {
                Text("Button")
            })
        }
    }

    Structure 내에서 변수를 바꾸려고 하면 'Cannot assign to property: 'self' is immutable 이라는 에러메시지를 띄우게되죠 . 

    이때, @State 를 변수에 씌워주게되면 struct 밖의 SwiftUI 가 관리하는 shared Storage 로 storage를 옮겨서 저장하게 됩니다. 

    이렇게 되면 SwiftUI는 @State 로 씌워진 data 를 그대로 유지하면서 struct 를 마음껏 destroy, recreate 할 수 있게 돼요. 

     

    @State 가 씌워진 structs 는 간단한 type 으로 되는게 좋아요. (String, Int 등)  그리고 다른 Views 과는 공유되지 않습니다. 

    만약 다른 Views 과 어떤 값을 공유하고싶다면, @ObservableObject 또는 @EnvironmentObject 와 함께 쓰시게 될거에요. 

     

    Apple 은 @State 의 특성을 다시 스스로 생각해보기 위해 private keyword 를 붙이길 권장합니다. ( 안붙여도 상관 없지만 권장)

     

    @State private var username = ""

     

    Tip: 

    Reference types 의 값을 track 하기 위해 @State 를 붙이셔도 되지만, 값들이 변할 때 notified 되지는 않아요. 

    이런 방식은 Observable protocol 을 conform 하지 않는 classes 에 대해 사용하시면 아주아주 유용합니다.

     

     


     

     

    @Binding ( 화면 전환 하면서 값 연결시키기)

    @Binding wrapper는 두 Views 에서 값을 공유하기 위해 쓰입니다. 

    이는 여러 Views 에서 공유되기 위해 reference type 으로 만들어진 @ObservedObject or @EnvironmentObject와는 달라요. 

     

    먼저, 

    struct ContentView: View {
        
        @State var isShowing = false
        
        var body: some View {
            
            Button("button to detailView") {
                isShowing = true
            }
            .sheet(isPresented: $isShowing, content: {
                DetailView(isDetailViewShowing: $isShowing)
            })
        }
    }
    
    struct DetailView: View {
    
        @Binding var isDetailViewShowing : Bool
        
        var body: some View {
            Button("Dismiss!") {
                isDetailViewShowing = false
            }
        }
    }

     

     

    로직을 단순히 설명드리면, ContentView 에서 DetailView 를 present 할지 말지 결정하는 변수로 isShowing 을 선언했어요. 

    그 후 DetailView 가 present 된 상태에서 ContentView 의 isShowing 변수를 변화시키기 위해서

    DetailView 에서 그 연결고리가 될 변수를 @Binding 을 이용해서 만들었어요. (isDetailViewShowing)

     

    ContentView 에서 버튼을 누르면 isShowing 이 true 로 되고, 따라서 sheet 의 isPresented 값에 true 가 넘어가면서  DetailView 가 present 되게 됩니다. (이때, DetailView의 isDetailViewShowing 과 ContentView의 isShowing 값이 서로 연결돼요. (isDetailViewShowing property에 $isShowing 값을 넣어줌으로써 ( Binding ) ) )

     

    DetailView가 present 된 후에, "Dismiss" 버튼을 누르면 isDetailViewShowing 값이 false 로 되면서, ContentView의 isShowing 값도 false 로 , 결국 해당 뷰 (DetailView) 가 dismiss 하게 된답니다~~


     

    이번엔 다른 예제입니다. 

     

    좌측부터 차례대로 SimpleView, SelectionView, SimpleView

     

     

    이번 예제에서는 Binding 을 두 쌍에 대해 하고있어요.

    한 쌍은 화면이 나타날지 사라질지에 관한 것이고, (isShowingSheet, showingSelectionView)

    한 쌍은 SimpleView 에서 나타날 이미지를 결정해요. ( isNight, isNight ) 

    struct SimpleView: View {
        
        @State private var isNight = true
        @State private var isShowingSheet = false
        
        var body: some View {
            ZStack {
                VStack {
                    Image(systemName: isNight ? "moon.stars.fill" : "cloud.sun.fill")
                    Button {
                        isShowingSheet = true
                    } label: {
                        Label("Change Time Of Day", systemImage: "clock.fill")
                            .foregroundColor(.black)
                    }
                }
            }
            .sheet(isPresented:$isShowingSheet,
                   content: {
                SelectionView(
                    isNight: $isNight,
                    showingSelectionView: $isShowingSheet
                )
            })
        }
    }
    struct SelectionView: View {
        
        @Binding var isNight: Bool
        @Binding var showingSelectionView: Bool
        
        var body: some View {
            VStack {
                Button {
                    isNight = true
                    showingSelectionView = false
                } label: {
                    Label("Make Night", systemImage: "moon.stars.fill")
                        .foregroundColor(.white)
                }
     
                Button {
                    isNight = false
                    showingSelectionView = false
                } label: {
                    Label("Make Day", systemImage: "cloud.sun.fill")
                }
            }
        }
    }

    Binding 의 첫 예제에서 화면을 나타나게 할지 말지는 설명했으므로 이번 예시에서는 isNight 변수 ( SimpleView 에서의 이미지 결정) 에 대해 알아보도록 해요. 

     

    SimpleView에서 isNight 에 따라 보이는 이미지가 달라져요

    Image(systemName: isNight ? "moon.stars.fill" : "cloud.sun.fill")

     

    SimpleView 에서 SelectionView 로 이동할 때,

    isNight -> isNight

    isShowingSheet -> showingSelectionView

    두 쌍의 변수들이 Bind 되게 됩니다.

    SelectionView 에서는 두 버튼이 있고, 첫 버튼은 isNight 을 true로, 나머지 버튼을 false 로 설정합니다.

    이렇게 할 시 SimpleView 에서의 isNight 변수도 서로 Binding 되어있기 때문에 변하게 되고,

     

     

    그 후 과정은 showingSelectionView 가 false 로 변하면서 해당 View (SelectionView) 가 dismiss 하게 돼요 !

     

    (위 예제 코드에서는 핵심만 보기 쉽게 하기 위해 색상, padding, cornerRadius 등은 포함하지 않았어요. 아래 link에는 있습니다.)

     

    완성 소스코드 github link : https://github.com/hanmok/BindingPractice 

             간단한     clone link: https://github.com/hanmok/BindingPractice.git

     

    참조 링크

    https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-state-property-wrapper

    https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-binding-property-wrapper

    https://www.youtube.com/watch?v=lgtB3WLEOYg

     

     

     

    What is the @State property wrapper? - a free SwiftUI by Example tutorial

    Was this page useful? Let us know! 1 2 3 4 5

    www.hackingwithswift.com

     

    What is the @Binding property wrapper? - a free SwiftUI by Example tutorial

    Was this page useful? Let us know! 1 2 3 4 5

    www.hackingwithswift.com

     

Designed by Tistory.