SwiftUI: @Binding चर के साथ एक कस्टम init कैसे लागू करें


102

मैं एक पैसा इनपुट स्क्रीन पर काम कर रहा हूं और 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
    }
    ...
}

जवाबों:


164

अरे! तुम इतने करीब थे। इसे आपको इसी तरह करना होगा। आपने एक डॉलर चिह्न (बीटा 3) या अंडरस्कोर (बीटा 4) को याद किया, और या तो अपनी राशि संपत्ति के सामने स्वयं, या राशि पैरामीटर के बाद .value। ये सभी विकल्प काम करते हैं:

आप देखेंगे कि मैंने @Stateइनडेसिमल को हटा दिया , अंत में स्पष्टीकरण की जाँच करें।

यह संपत्ति का उपयोग कर रहा है (इसके सामने स्वयं को रखें):

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
    }
}

या का उपयोग कर। के बाद (लेकिन स्वयं के बिना, क्योंकि आप पारित पैरामीटर का उपयोग कर रहे हैं, न कि संरचना की संपत्ति):

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) और संपत्ति (राशि) के लिए अलग-अलग नामों का उपयोग करते हैं, इसलिए आप स्पष्ट रूप से देखते हैं कि आप प्रत्येक का उपयोग कब कर रहे हैं।

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 की जाँच करें - आधुनिक स्विफ्ट एपीआई डिज़ाइन और 23:12 पर जाएं।

जैसा कि आपने खोजा था, initilizer से @State वैरिएबल को संशोधित करने से निम्नलिखित त्रुटि होगी: थ्रेड 1: घातक त्रुटि: View.body के बाहर स्टेट एक्सेस करना । इससे बचने के लिए, आपको या तो @ हटा देना चाहिए। जो समझ में आता है क्योंकि इनडिसिमल सत्य का स्रोत नहीं है। इसका मान राशि से लिया गया है। हालांकि @State को हटाकर, includeDecimalराशि में परिवर्तन होने पर अपडेट नहीं होगा। इसे प्राप्त करने के लिए, सबसे अच्छा विकल्प, आपके शामिलकमल को एक गणना की गई संपत्ति के रूप में परिभाषित करना है, ताकि इसका मूल्य सत्य (राशि) के स्रोत से प्राप्त हो। इस तरह, जब भी राशि बदलती है, तो आपका शामिलडिमल भी करता है। यदि आपका दृश्य शामिल हैंDecimal पर निर्भर करता है, तो इसे बदलने पर अद्यतन करना चाहिए:

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 { ... }
}

जैसा कि रॉब मेयो द्वारा इंगित किया गया है , आप स्टेट वैरिएबल को इनिशियलाइज़ करने के लिए $$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 > 0कीThread 1: Fatal error: Accessing State<Bool> outside View.body
keegan3d

खैर, यह समझ में आता है। @Stateचर को सत्य के स्रोत का प्रतिनिधित्व करना चाहिए। लेकिन आपके मामले में आप उस सत्य की नक़ल कर रहे हैं, क्योंकि इनडिसिमल के मूल्य को आपके सत्य के वास्तविक स्रोत से प्राप्त किया जा सकता है। आपके पास दो विकल्प हैं: 1. आप एक निजी संस्करण (कोई @State) को शामिल नहीं करते हैं, या इससे भी बेहतर 2. आप इसे एक संगणित संपत्ति बनाते हैं जो इसके मूल्य को प्राप्त करता है amount। इस तरह, अगर राशि बदलती है, includeDecimalतो भी करता है। आपको इसे इस तरह से घोषित करना चाहिए: private var includeDecimal: Bool { return round(amount)-amount > 0 }और self.includeDecimal = ...
20:00

हम्म, मैं includeDecimalइसे देखने में @State चर के रूप में जरूरत है इसलिए इसे बदलने में सक्षम होने की जरूरत है। मैं वास्तव में इसे शुरुआती मूल्य के साथ शुरू करना चाहता हूं
keegan3d

1
@ Let_Create मैंने उन्हें केवल एक बार पूरी तरह से देखा, लेकिन फॉरवर्ड बटन के लिए भगवान का धन्यवाद ;-)
kontiki

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 var showFavorited: Bool

Toggle(isOn: $showFavorited) {
    Text("Change filter")
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.