SwiftUI : @Binding 변수로 사용자 지정 초기화를 구현하는 방법


103

저는 돈 입력 화면에서 작업 중이며 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
    }
    ...
}

답변:


166

아아! 당신은 너무 가까웠습니다. 이것이 당신이하는 방법입니다. 달러 기호 (베타 3) 또는 밑줄 (베타 4)이 누락되었으며 금액 속성 앞의 self 또는 금액 매개 변수 뒤의 .value가 누락되었습니다. 이 모든 옵션이 작동합니다.

@Statein 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)

감사! 이것은 많은 도움이되었습니다! 나는에 런타임 오류가 무엇입니까 self.includeDecimal = round(self.amount)-self.amount > 0Thread 1: Fatal error: Accessing State<Bool> outside View.body
keegan3d

글쎄, 그건 말이 되네요. @State변수는 진실의 근원을 나타내야합니다. 그러나 귀하의 경우에는 그 진실을 복제하고 있습니다. includeDecimal의 값은 양인 실제 진실 소스에서 파생 될 수 있기 때문입니다. 다음과 같은 두 가지 옵션이 있습니다. 1. includeDecimal을 private var (@State 없음)로 만들거나 더 좋습니다. 2.에서 값을 파생하는 계산 된 속성으로 만듭니다 amount. 이렇게하면 금액이 변경되는 경우 includeDecimal에도 마찬가지입니다. 다음 private var includeDecimal: Bool { return round(amount)-amount > 0 }과 같이 선언해야합니다 : 그리고 제거self.includeDecimal = ...
kontiki

흠, 변경할 수 있어야 includeDecimal하므로 뷰에서 @State 변수로 필요합니다. 정말 시작 값으로 초기화하고 싶습니다
keegan3d

1
@ Let's_Create 나는 완전히 한 번만를 보았다하지만 주셔서 감사합니다 신 전달의 버튼 ;-)
콘티키

1
정말 좋은 설명입니다. 감사합니다. 나는 이제 .value가로 대체되었다고 생각 .wrappedValue합니다. 대답을 업데이트하고 베타 옵션을 제거하면 좋을 것입니다.
user1046037

11

당신은 (댓글에서) "나는 바꿀 수 있어야한다 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.)


오 대단해, ​​두 배의 $$는 내가이 부분에 필요한 것이었다!
keegan3d

3

2020 년 중반 이후로 요약 해 보겠습니다.

에 관해서 @Binding amount

  1. _amount초기화 중에 만 사용하는 것이 좋습니다. 그리고 self.$amount = xxx초기화 중에 이런 식으로 할당하지 마십시오.

  2. amount.wrappedValue그리고 amount.projectedValue자주 사용되지 않지만 같은 경우를 볼 수 있습니다

@Environment(\.presentationMode) var presentationMode

self.presentationMode.wrappedValue.dismiss()
  1. @binding의 일반적인 사용 사례는 다음과 같습니다.
@Binding var showFavorited: Bool

Toggle(isOn: $showFavorited) {
    Text("Change filter")
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.