[SwiftUI] Property Wrapper (2)

DongHeon·2023년 10월 18일
0

SwiftUI

목록 보기
2/6
post-thumbnail

이번에는 간단한 예시를 가지고 State, Binding에 대해서 알아보겠습니다.

버튼을 눌러 숫자를 증가 감소시키는 화면이 있습니다. 먼저 ContentView 코드를 살펴보겠습니다.

struct ContentView: View {
    @State var number: Int = 0
    
    var body: some View {
        VStack {
            Text(String(number))
                .font(.largeTitle)
                .bold()
            
            HStack {
            	Button {
                	number -= 1
            	} label: {
                	Text("minus")
                    	.foregroundColor(.white)
                    	.padding()
                    	.padding(.horizontal)
                    	.background(.red)
                    	.cornerRadius(10)
            	}
            
            	Spacer()
            
            	Button {
                	number += 1
            	} label: {
                	Text("plus")
                    	.foregroundColor(.white)
                    	.padding()
                    	.padding(.horizontal)
                    	.background(.blue)
                    	.cornerRadius(10)
            	}

        	}
        	.padding()
        }
        .padding()
    }
}

코드를 보면 numberState로 선언되어 있는 걸 볼 수 있습니다.

공식 문서를 보면 State는 값을 읽고 쓸 수 있는 Property Wrapper라고 합니다.

여기서 궁금한 점은 굳이 @State를 붙여야 하는가입니다. 그냥 number를 변경시키면 되지 않을까 생각할 수 있습니다.

@State 키워드를 제거하게 되면 사진과 같은 에러를 확인할 수 있습니다.
Error

ContentView는 struct로 구현되어 있습니다. 즉 struct는 immutable 한 성격을 가지고 있기 때문에 자신이 가지고 있는 property를 그냥 변경 시킬 수 없습니다. 그렇기 때문에 @State를 사용해야 합니다.

이제 Binding에 대해서 알아보겠습니다. 그전에 먼저 위에 코드가 지저분한 것 같으니 Button을 만드는 코드를 먼저 분리하겠습니다.

struct UpDownButton: View {
    @Binding var number: Int
    
    var body: some View {
        HStack {
            Button {
                number -= 1
            } label: {
                Text("minus")
                    .foregroundColor(.white)
                    .padding()
                    .padding(.horizontal)
                    .background(.red)
                    .cornerRadius(10)
            }
            
            Spacer()
            
            Button {
                number += 1
            } label: {
                Text("plus")
                    .foregroundColor(.white)
                    .padding()
                    .padding(.horizontal)
                    .background(.blue)
                    .cornerRadius(10)
            }
        }
        .padding()
    }
}

UpDownButton의 number 앞에는 @Binding이 붙어있습니다. Binding은 Source의 값을 읽고 쓸 수 있는 Property Wrapper입니다.

Binding을 사용하면 데이터를 저장하는 속성과 데이터를 변경하고 표시하는 화면 간의 양방향 연결을 만들 수 있습니다. Binding을 통해 데이터를 저장하는 대신 Property는 다른 곳에 저장된 소스에 연결합니다.

그럼 수정 된 ContentView 코드를 보겠습니다.

struct ContentView: View {
    @State var number: Int = 0
    
    var body: some View {
        VStack {
            Text(String(number))
                .font(.largeTitle)
                .bold()
            
            UpDownButton(number: $number)
        }
        .padding()
    }
}

코드를 보면 이제 상위 뷰는 ContentView가 되고 하위 뷰는 UpDownButton이 됩니다. 즉 하위 뷰에서 number를 수정하지만 ContentView의 number에 연결되어 있다고 이해하면 될 것 같습니다.

Binding 속성을 전달하고 싶다면 ($) 기호를 사용해야 합니다.

정리

SwiftUI는 각각의 View를 객체화해 조합해서 사용할 수 있다는 큰 장점이 있습니다. 여기서 struct를 통해 각각의 View를 구현하게 되는데 struct 특성 상 자신의 property를 그냥 변경할 수 없습니다. 또한 같은 데이터를 공유하는 View 사이를 연결 시켜주기 위해서는 @State와 @Binding을 사용해야 합니다.

0개의 댓글