@Binding 프로퍼티 래퍼는 뷰간 데이터를 전달할 때 사용됩니다
@Binding은 누구나 사용해 봤을 것입니다. 하지만 @Binding을 커스텀화하여 사용할 수도 있다는 사실은 몰랐습니다.
간단하게 3개의 View를 만들어보겠습니다.
title은 각 View에서 사용자에게 보여줄 Text에 들어갈 string이며 errorTitle은 에러 메시지 showError는 에러 메시지를 보여주는 유무
@State var title: String = "Start"
@State private var errorTitle: String? = nil
@State private var showError: Bool = false
첫 번째 View
다음은 일반적으로 평소에 많이 쓰는 @State 프로퍼티 래퍼와 @Binding 프로퍼티 래퍼입니다.
ChildView(title: $title)
struct ChildView: View {
@Binding var title: String
var body: some View {
Text(title)
.onAppear {
title = "NEW TITLE"
}
}
}
두 번째 View
다음 뷰는 setTitle: (String) -> Void를 통해서 클로저를 통해 title의 값을 바꾸는 방법입니다.
ChildView2(title: title) { newTitle in
title = newTitle
}
struct ChildView2: View {
let title: String
let setTitle: (String) -> Void
var body: some View {
Text(title)
.onAppear {
setTitle("NEW TITLE 2")
}
}
}
세 번째 View 커스텀 Binding
다음은 커스텀 바인딩을 통해서 뷰를 만드는 코드입니다. 확인해보면 Binding(get: () -> value, set: (Value) -> Void) 를 사용하고 있습니다. get은 가져올 Binding 데이터를 의미하며 set은 설정할 Binding 데이터를 의미합니다.
다시 쉽게 말해 get은 ChildView3에서 title값을 get 해서 사용하고 set은 ChildView3에서 set한 값을 title에 넣는 것입니다.
ChildView3(title: Binding(get: {
return title
}, set: { newValue in
title = newValue
}))
아래 title.wrappedValue 를 사용하고 있는데 wrappedValue는 Binding에 의해 참조하고 있는 값을 의미합니다. 즉 값이 바뀌게 된다면 위에서 만든 Binding 클로저 set 부분이 수행되어 바뀐 값(newValue)인 "NEW TITLE3"를 @State 프로퍼티 래퍼인 title에 넣습니다.
struct ChildView3: View {
let title: Binding<String>
var body: some View {
Text(title.wrappedValue)
.onAppear {
title.wrappedValue = "NEW TITLE3"
}
}
}
커스텀 바인딩을 사용했을 때 장점
위에서는 어떻게 사용하는지 느낌을 알아봤습니다. 이제 어떤 점이 좋아지는지에 대해서 설명하겠습니다.
평소에 버튼을 누르면 다음 코드처럼 에러 메시지를 변경하고 에러 메시지를 .alert() 메서드로 나타내는 방법을 사용하였습니다.
Button("클릭") {
errorTitle = "새로운 에러"
showError.toggle()
}
하지만 이때 커스텀 바인딩을 구현하게 된다면 showError.toggle() 를 따로 만들지 않아도 됩니다. 방법은 다음과 같습니다.
알림 메시지로는 errorTitle 값을 보여주며 알림을 보여주는 조건은 isPresented로 받을 값을 get으로 설정하고 알림 메시지가 보여진 다음으로는 set을 통해서 errorTitle의 값을 설정합니다.
다시 쉽게 말해 get은 .alert에서 errorTitle값이 없으면 false 값이 있으면 true로 메시지가 나타나며 메시지 알림이 없어지면 set으로 다시 errorTitle의 값을 지워줍니다.
.alert(errorTitle ?? "Error", isPresented: Binding(get: {
return errorTitle != nil ? true : false
}, set: { newValue in
errorTitle = nil
})) {
Button("확인") {
}
}
이렇게 구현하면 showError.toggle() 메서드 없이 가능해집니다.
Button("클릭") {
errorTitle = "새로운 에러"
}
extension을 이용하여 클린하게 만들기
extension을 이용하여 코드를 좀 더 클린하게 만들 수 있습니다. 다음은 Binding을 extension으로 확장하여 만든 것입니다.
안에 코드는 위에서 구현한 코드와 내용이 같으며 코드를 더 간결하게 사용 가능하게 합니다.
extension Binding where Value == Bool {
init<T>(value: Binding<T?>) {
self.init {
value.wrappedValue != nil
} set: { newValue in
if !newValue {
value.wrappedValue = nil
}
}
}
}
.alert(errorTitle ?? "Error", isPresented: Binding(value: $errorTitle)) {
Button("확인") {
}
}
'SwiftUI' 카테고리의 다른 글
공공 데이터 지도에 띄우기 (with 네이버 지도) (0) | 2024.05.13 |
---|---|
custom error (0) | 2024.05.11 |
지도에서 내 현재 위치 가져오기 (네이버 지도) (0) | 2024.05.09 |
카메라를 이용하여 QR code 스캔하기 (0) | 2024.05.07 |
네이버 지도 (마커 눌렀을 때 데이터 정보 불러오기 with 클러스터링) (0) | 2024.05.04 |