k-coding

SwiftUI @State, @Binding 본문

iOS/Swift UI

SwiftUI @State, @Binding

chkhn_oiiu 2022. 5. 1. 23:55

SwiftUI @State, @Binding

 

SwiftUI에서는 처음 생성할때도 그렇고 기본적으로 구조체에서 View를 구현합니다.

 

그런데 원래 구조체에서는 변수값을 변경할 수 없다고 배웠었는데요..?

 

그렇다면 SwiftUI에서는 변수를 설정하면 값을 바꿀수 없는걸까요?

 

원래 UIkit에서는 구조체에서 변수를 변경할 때 mutating을 사용해주었는데요.

 

View 프로토콜의 body는 {  get  }으로 되어 있으며, nonmutating 구현을 요구합니다.

 

따라서 SwiftUI에서는 구조체안에서 변수를 바꿀때  @State를 사용하게 됩니다.

 

 

@State ( 상태 프로퍼티 )

@State는  현재 상태를 나타내는 속성으로써 View의 어떤 값을 저장하는 데 사용합니다.

 

예를 들어 String, Int, Boolean등 간단한 데이터 타입을 저장하며

 

상태 값은 해당 뷰에 속한 것이기 때문에 Private프로퍼티로 선언되어야 합니다.

 

struct ContentView: View { 
    @State private var isOn = true 
    @State private var name = ""
}

 

상태 프로퍼티 값이 변경 되었단 말은 해당 프로퍼티가 선언된 뷰 계층구조를 다시 rendering해야 한다는 말로

 

계층구조 안에 있는 모든 뷰를 재 생성하고 표시해야합니다.

 

결국 값이 바뀌는 프로퍼티에 의존하는 뷰들은 모두 최신 값이 반영된 값으로 업데이트 됩니다.

 

상태 프로퍼티를 선언하면 레이아웃에 있는 뷰와 바인딩 할 수 있게되는데

 

바인딩 된 뷰에서는 어떤 값의 변경이 발생하면 해당 상태 프로퍼티를 자동으로 업데이트 해줍니다.

 

바인딩은 프로퍼티 앞에 $를 붙여주면됩니다.

struct ContentView: View {
    @State private var isOn = true
    @State private var name = ""
    
    var body : some View {
        VStack {
            TextField("이름을 입력해 주십시오.", text: $name)
                .multilineTextAlignment(.center)
                .font(.largeTitle)
                .foregroundColor(.black)
                
            Text("이름은 : \(name)")
                .fontWeight(.bold)
                .foregroundColor(.black)
        }
    }
}

 

 

위 코드에서 보셔야 할 점이  TextField에서는 name이라는 변수를 받기위해 $ 를 사용했지만,

 

Text에서는 $ 없이 그냥 name만 사용되었다.

 

이유는 TextField에서 $name을 통하여 상태 프로퍼티에 할당된 값을 변경없이 사용하기 때문입니다.

 

항상 $ 붙이는게 아니라는 점 !!

 

 

 

@Binding

@Binding은 하위 뷰에서 상위 뷰에 선언된 상태프로퍼티에 접근할 수 있게 해줍니다.

 

예를들어 아래와 같은 하위 뷰가 추가되었다고 생각해봅시다.

 

struct NameView: View {
    
    var body: some View {
        Text("반갑습니다. \(name)님")
            .fontWeight(.bold)
            .foregroundColor(.black)
            .font(.system(size: 60))
    }
    
}

 

위~에 작성했던 소스를 참고하시면 거기서 상태 프로퍼티로 name을 사용한것을 이 뷰에서도 재사용하는것을 눈치챌 수 있습니다.

 

근데 이렇게만 작성하면 바로 에러가 등장하게됩니다! 또잉..

 

NameView의 Text는 계속 name 상태프로퍼티에 접근해야하지만, 이제 메인뷰의 범위 밖으로 벗어나버렸기 때문입니다.

 

따라서 NameView입장에서는 name은 정의되어있지않은 변수인 것이죠.

 

이러한 문제를 해결해주는것이 @Binding입니다.

 

@Binding var name : String

 

다음과 같은 형식으로 하위 뷰가 호출 될 때 상태 프로퍼티에 대한 바인딩을 전달하면 됩니다.

 

struct ContentView: View {
    @State private var isOn = true
    @State private var name = ""
    
    var body : some View {
        VStack {
            TextField("이름을 입력해 주십시오.", text: $name)
                .multilineTextAlignment(.center)
                .font(.largeTitle)
                .foregroundColor(.black)
            Text("이름은 : \(name)")
                .fontWeight(.bold)
                .foregroundColor(.black)
        }
    }
}

struct NameView: View {
    
    @Binding var name: String
    var body: some View {
        Text("반갑습니다. \(name)님")
            .fontWeight(.bold)
            .foregroundColor(.black)
            .font(.system(size: 60))
    }
    
}

'iOS > Swift UI' 카테고리의 다른 글

SwiftUI Divider, Spacer  (0) 2022.05.05
SwiftUI WebView (UIViewRepresentable)  (0) 2022.05.05
SwiftUI Navigation 연결  (0) 2022.05.01
SwiftUI (HStack / VStack)  (0) 2022.05.01
SwiftUI 알아보기  (0) 2022.04.30
Comments