SwiftUI: @Binding 変数を使用してカスタム init を実装する方法 質問する

SwiftUI: @Binding 変数を使用してカスタム init を実装する方法 質問する

init私はお金の入力画面に取り組んでおり、初期化された金額に基づいて状態変数を設定するカスタムを実装する必要があります。

次のようにすればうまくいくと思いました:

struct AmountView : View {

    @Binding var amount: Double   
    @State var includeDecimal = false

    init(amount: Binding<Double>) {
        self.amount = amount
        self.includeDecimal = round(amount)-amount > 0
    }
}

ただし、次のようなコンパイラ エラーが発生します。

'Binding' 型の値を 'Double' 型に割り当てることはできません

init構造体を受け取るカスタム メソッドを実装するにはどうすればよいですかBinding?

ベストアンサー1

ああ! かなり近かったのに。やり方はこうです。ドル記号 (ベータ 3) またはアンダースコア (ベータ 4) を忘れました。また、amount プロパティの前に self があるか、amount パラメータの後に .value があります。これらのオプションはすべて機能します。

@Stateを削除したことがわかりますincludeDecimal。最後の説明を確認してください。

これはプロパティを使用しています (その前に 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(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
    }
}

プロパティラッパー (@Binding) のおかげで、.value はプロパティには不要です。プロパティラッパーは、.value を不要にするアクセサーを作成します。ただし、パラメータにはそのようなものはなく、明示的に行う必要があります。プロパティラッパーについて詳しく知りたい場合は、WWDC セッション 415 - 最新の Swift API 設計23:12にジャンプします。

ご存知のとおり、初期化子から @State 変数を変更すると、次のエラーが発生します:スレッド 1: 致命的なエラー: View.body の外部で State にアクセスしています。これを回避するには、@State を削除する必要があります。includeDecimal は真実のソースではないため、これは理にかなっています。その値は amount から派生します。ただし、@State を削除すると、includeDecimalamount が変更されても更新されません。これを実現するには、includeDecimal を計算プロパティとして定義し、その値が真実のソース (amount) から派生するようにするのが最善のオプションです。このようにすると、amount が変更されるたびに、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が指摘しているように、 State 変数を初期化するには$$varName(beta 3) または(beta4)を使用することもできます。_varName

// Beta 3:
$$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)

// Beta 4:
_includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)

おすすめ記事