[swift] SwiftUI : @Binding 변수로 사용자 지정 초기화를 구현하는 방법
저는 돈 입력 화면에서 작업 중이며 init
초기화 된 금액에 따라 상태 변수를 설정하는 사용자 지정 을 구현해야합니다 .
이것이 작동 할 것이라고 생각했지만 다음과 같은 컴파일러 오류가 발생합니다.
Cannot assign value of type 'Binding<Double>' to type 'Double'
struct AmountView : View {
@Binding var amount: Double
@State var includeDecimal = false
init(amount: Binding<Double>) {
self.amount = amount
self.includeDecimal = round(amount)-amount > 0
}
...
}
답변
아아! 당신은 너무 가까웠습니다. 이것이 당신이하는 방법입니다. 달러 기호 (베타 3) 또는 밑줄 (베타 4)이 누락되었으며 금액 속성 앞의 self 또는 금액 매개 변수 뒤의 .value가 누락되었습니다. 이 모든 옵션이 작동합니다.
@State
in includeDecimal을 제거했음을 알 수 있으며 마지막에 설명을 확인하십시오.
이것은 속성을 사용하고 있습니다 (자신을 앞에 두십시오).
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(amount: Binding<Double>) {
// self.$amount = amount // beta 3
self._amount = amount // beta 4
self.includeDecimal = round(self.amount)-self.amount > 0
}
}
또는 뒤에 .value를 사용합니다 (그러나 self는 사용하지 않습니다. 구조체의 속성이 아닌 전달 된 매개 변수를 사용하기 때문입니다) :
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(amount: Binding<Double>) {
// self.$amount = amount // beta 3
self._amount = amount // beta 4
self.includeDecimal = round(amount.value)-amount.value > 0
}
}
이것은 동일하지만 매개 변수 (withAmount)와 속성 (amount)에 대해 다른 이름을 사용하므로 각각을 사용할 때 명확하게 알 수 있습니다.
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(withAmount: Binding<Double>) {
// self.$amount = withAmount // beta 3
self._amount = withAmount // beta 4
self.includeDecimal = round(self.amount)-self.amount > 0
}
}
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal = false
init(withAmount: Binding<Double>) {
// self.$amount = withAmount // beta 3
self._amount = withAmount // beta 4
self.includeDecimal = round(withAmount.value)-withAmount.value > 0
}
}
.value를 불필요하게 만드는 접근자를 만드는 속성 래퍼 (@Binding) 덕분에 속성에 .value가 필요하지 않습니다. 그러나 매개 변수에는 그런 것이 없으며 명시 적으로 수행해야합니다. 속성 래퍼에 대해 자세히 알아 보려면 WWDC 세션 415-Modern Swift API Design을 확인 하고 23:12로 이동하세요.
발견 한대로 초기화 프로그램에서 @State 변수를 수정하면 다음 오류가 발생합니다. Thread 1 : Fatal error : Accessing State outside View.body . 이를 방지하려면 @State를 제거해야합니다. includeDecimal이 진실의 소스가 아니기 때문에 의미가 있습니다. 그 가치는 금액에서 파생됩니다. 그러나 @State를 제거 includeDecimal
하면 금액이 변경되면 업데이트되지 않습니다. 이를 달성하기위한 최선의 옵션은 includeDecimal을 계산 된 속성으로 정의하여 그 값이 진실의 출처 (금액)에서 파생되도록하는 것입니다. 이렇게하면 금액이 변경 될 때마다 includeDecimal도 변경됩니다. 뷰가 includeDecimal에 의존하는 경우 변경 될 때 업데이트되어야합니다.
struct AmountView : View {
@Binding var amount: Double
private var includeDecimal: Bool {
return round(amount)-amount > 0
}
init(withAmount: Binding<Double>) {
self.$amount = withAmount
}
var body: some View { ... }
}
rob mayoff에 표시된대로 $$varName
(베타 3) 또는 _varName
( 베타 4)를 사용 하여 상태 변수를 초기화 할 수도 있습니다 .
// Beta 3:
$$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)
// Beta 4:
_includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)
답변
당신은 (댓글에서) “나는 바꿀 수 있어야한다 includeDecimal
“고 말했다. 변화한다는 것은 무엇을 의미 includeDecimal
합니까? amount
(초기화 시간에) 정수 인지 여부에 따라 초기화하고 싶을 것 입니다. 괜찮아. 경우에 따라서 무슨 일이 includeDecimal
있다 false
가 나중에 당신이로 변경 true
? 어떻게 든 강제 amount
로 정수가 아니겠습니까?
어쨌든, 당신은 수정할 수 없습니다 includeDecimal
에서 init
. 그러나 다음 init
과 같이 에서 초기화 할 수 있습니다 .
struct ContentView : View {
@Binding var amount: Double
init(amount: Binding<Double>) {
$amount = amount
$$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)
}
@State private var includeDecimal: Bool
(참고 어떤 점에서$$includeDecimal
구문이 변경됩니다 _includeDecimal
.)
답변
2020 년 중반 이후로 요약 해 보겠습니다.
에 관해서 @Binding amount
-
_amount
초기화 중에 만 사용하는 것이 좋습니다. 그리고self.$amount = xxx
초기화 중에 이런 식으로 할당하지 마십시오. -
amount.wrappedValue
그리고amount.projectedValue
자주 사용되지 않지만 같은 경우를 볼 수 있습니다
@Environment(\.presentationMode) var presentationMode
self.presentationMode.wrappedValue.dismiss()
- @binding의 일반적인 사용 사례는 다음과 같습니다.
@Binding var showFavorited: Bool
Toggle(isOn: $showFavorited) {
Text("Change filter")
}