Swift

어서와 @Binding은 처음이지?

Thor_yeom 2023. 1. 25. 16:11

@State를 사용하면 짝으로 활용되는게 Binding입니다. 그럼 Binding이 무엇인가요? 

bind의 사전적 의미로 보면 묶다, 감다를 나타냅니다. 사전적 의미에서 느껴지는 느낌을 갖고 binding에 대해 알아봅시다.

 

결론은 @State 속성으로 선언된 프로퍼티와 연결되어 있다고 생각하면 됩니다. 

첫 화면 에서 보여지는 Text를 다른 화면에서도 똑같은 값을 보여주기 위해선 어떻게 하면 좋을까? 답은 @State 로 설정되어 있는 값을 

@Binding해서 나타내고자 하는 뷰에 만들어주면 됩니다.

 

영상을 보시면 

 

+1씩 증가 시키고 시트뷰를 누르면 다른 뷰에서도 같은 값이 나오는 것을 볼 수 있습니다. 어떻게 가능 한거죠??

주가 되는 뷰에 @State를 한 번만 선언해주고, 다른 뷰들에서 사용하기 위해서는 @Binding을 해주면 끝! 참 쉽죠?

 

하나씩 코드를 뜯어보면서 살펴봅시다. 

 

struct ContentView: View {
    // 1씩 증가되는 것이 number이기 때문에 버튼을 눌렀을때 상태가 변하므로 @State로 설정
    @State private var number: Int = 0
    // Bool값으로 바텀 시트를 올릴수 있도록 버튼을 눌렀을때 false, true값으로 변해야하기 때문에
    // @State로 설정
    @State private var isShowing: Bool = false
    var body: some View {
        VStack {
            
            Text("\(number)")
                .font(.largeTitle)
            
            Button {
                number += 1
            } label: {
                Text("+1씩 증가시키기 ")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)
            
            Button {
                isShowing.toggle()
            } label: {
                Text("시트뷰")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)
            
            
            Button {
                number = 0
            } label: {
                Text("리셋")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)

        }
    }
}

 

여기서 중요한 점은 다른뷰에서도 binding을 통해 값을 보여주고 싶을때는 쉽게 하면 됩니다. 어때요 참 쉽죠?


import SwiftUI

struct ContentView: View {
    // 1씩 증가되는 것이 number이기 때문에 버튼을 눌렀을때 상태가 변하므로 @State로 설정
    @State private var number: Int = 0
    // Bool값으로 바텀 시트를 올릴수 있도록 버튼을 눌렀을때 false, true값으로 변해야하기 때문에
    // @State로 설정
    @State private var isShowing: Bool = false
    var body: some View {
        VStack {
            
            Text("\(number)")
                .font(.largeTitle)
            
            Button {
                number += 1
            } label: {
                Text("+1씩 증가시키기 ")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)
            
            Button {
                isShowing.toggle()
            } label: {
                Text("시트뷰")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)
            
            
            Button {
                number = 0
            } label: {
                Text("리셋")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)

        }
    }
}
// 다른 뷰를 만들때 @Binding var @State변수명: @State 자료형 
struct SheetView: View {
    @Binding var number: Int
    var body: some View {
    	// 보여주고 싶은 값 number
        Text("\(number)")
    }
}

 

그럼 저 뷰를 아래에서 위로 어떻게 올리면서 띄어주나요? 이것도 SwiftUI의 장점!! Apple에서 미리 메소드를 만들어 놓았으니 우리는 사용만 하면 됩니다. 

 

시트뷰 버튼을 눌렀을때 바텀 시트를 올리고 싶으니까 버튼이 끝나는 지점에 .sheet(isPresented ~ ) 를 사용해주면 됩니다.

여기서 보면 Binding<Bool>??? 이런게 뜨는데요, 제네릭 느낌인가?  그게 뭐지...? 쉽겠지만 우리는 연결만 하면 되니 일단은 넘어가도록 하겠습니다. 그럼 Binding에 isShowing을 넣어 보고 content에는 우리가 만들어준 SheetView를 만들어주도록 하겠습니다.

@bindng 적용

예??? 갑자기 오류가 뜨지만 친절하게도 개선 사항을 알려주네요  갓플!

해석을 해보자면 

'Boole' 유형의 'isShowing' 값을 예상 유형의 'Binding<Bool>'으로 변환할 수 없습니다. 대신 래퍼를 사용하십시오.

이게 무슨말이냐 쉽게 설명 드리면 

 

저희가 넣었던 isShowing은 자료형이 Bool값이고 placeHolder에 들어 갈 값의 자료형은

Binding<Bool>값이다! 아니 그래서 어떻게 하라고???...  오류 메세지 보면 insert '$'옆 Fix를 누르면 해결 완!

 

참 친절하게도 알려주죠? ㅎㅎ

 

저희가 만든 SheetView에 변수를 Binding 해줬기 때문에 여기서도 Binding<Int>이렇게 나오네요?  어라?  Binding<Int> 이렇게 나오면 변수 앞에 $표시만 붙이면 되는거 아녀? 네 맞습니다.

 

묻득 이런 생각이 드셨을 겁니다? ( 저만 이런 생각이 들었나요? ㅎㅎ) 아니 왜 SheetView에서 바인딩 해주는데 왜 자료형만 선언하고 값을 할당하지 않는거지? 그렇다고 ?(옵셔널)로 처리해 놓는것도 아니고...

 

뇌피셜 이지만...  아마도 상위뷰(ContentView)에서 @State로 선언이 되어있고, 이것이 주 이고, binding으로 처리 되는 것은 단지 주를  다른 뷰에 연결해서 보여주기 위함 이기 때문에 계속 변화하고, 상위뷰의 @State변수에 의존해야하기 때문에 자료형까지만 적는거 같습니다. (제가 생각한 부분이 틀릴수도 있으니... 고수님들 피드백 겸허히 수용하겠슴돠.. 그렇다고 너무 심하게 말하면 맘 아파요.. ㅠ

 

전체 코드는 이렇습니다. 

import SwiftUI

struct ContentView: View {
    // 1씩 증가되는 것이 number이기 때문에 버튼을 눌렀을때 상태가 변하므로 @State로 설정
    @State private var number: Int = 0
    // Bool값으로 바텀 시트를 올릴수 있도록 버튼을 눌렀을때 false, true값으로 변해야하기 때문에
    // @State로 설정
    @State private var isShowing: Bool = false
    var body: some View {
        VStack {
            
            Text("\(number)")
                .font(.largeTitle)
            
            Button {
                number += 1
            } label: {
                Text("+1씩 증가시키기 ")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)
            
            Button {
                isShowing.toggle()
            } label: {
                Text("시트뷰")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)
            .sheet(isPresented: $isShowing) {
                SheetView(number: $number)
            }
            
            
            Button {
                number = 0
            } label: {
                Text("리셋")
                    .font(.largeTitle)
            }
            .padding(.vertical, 20)

        }
    }
}
struct SheetView: View {
    @Binding var number: Int
    var body: some View {
        Text("\(number)")
    }
}

https://huniroom.tistory.com/entry/SwiftUI-state-property

 

[SwiftUI] state property 정리 (@state, @Binding)

요약 뷰 내부에서 특정 View 의 상태를 나타내는 변수 뷰내부에서 밖에 사용이 불가능함 때문에 private로 선언 하위 뷰나 다른 뷰에서 참조하기 위해선 @Binding 해야함 state property에 해당하는 변수

huniroom.tistory.com

https://velog.io/@nnnyeong/iOS-SwiftUI-State-Binding

 

[iOS] SwiftUI - @State, @Binding

SwiftUI 와 mvvm 을 경험하면서 정말 덕을 톡톡히 본 두가지 Property Wrapper 에 대해 정리해보자! State UIKit 을 사용했을 때는 어떠한 변수에 변화가 생기면 해당 변화를 직접 관찰하고 반영 해 주어야

velog.io