সুইফটুআই: কীভাবে @ বাঁধাকরণ ভেরিয়েবলগুলি সহ একটি কাস্টম ডিআই প্রয়োগ করতে হবে


95

আমি একটি অর্থ ইনপুট স্ক্রিনে কাজ করছি এবং 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
    }
    ...
}

উত্তর:


152

আঃ! আপনি খুব কাছাকাছি ছিল। এইভাবে আপনি এটি করেন। আপনি কোনও ডলারের চিহ্ন (বিটা 3) বা আন্ডারস্কোর (বিটা 4) মিস করেছেন, এবং হয় নিজের পরিমাণের সম্পত্তির সামনে নিজেই, অথবা পরিমাণের প্যারামিটারের পরে মূল্য নির্ধারণ করুন। এই সমস্ত বিকল্প কাজ করে:

আপনি দেখতে পাবেন যে আমি @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
    }
}

এটি একই, তবে আমরা প্যারামিটার (উইমাউন্ট) এবং সম্পত্তি (পরিমাণ) এর জন্য আলাদা আলাদা নাম ব্যবহার করি, সুতরাং আপনি প্রতিটি ব্যবহার করার সময় আপনি স্পষ্ট দেখতে পাবেন।

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

নোট করুন যে সম্পত্তিটির সাথে মূল্য মূল্য প্রয়োজন হয় না, সম্পত্তি র‌্যাপারকে (@ বাঁধাই করা) ধন্যবাদ, যা এমন অ্যাকসেসর তৈরি করে যা। মূল্যকে অযৌক্তিক করে তোলে। যাইহোক, প্যারামিটারের সাথে, এমন কোনও জিনিস নেই এবং আপনাকে এটি স্পষ্টভাবে করতে হবে। আপনি যদি সম্পত্তির মোড়ক সম্পর্কে আরও জানতে চান, ডাব্লুডাব্লুডিসি সেশন 415 - আধুনিক সুইফট এপিআই ডিজাইনটি পরীক্ষা করুন এবং 23:12 এ যান।

যেমন আপনি আবিষ্কার করেছেন, ইনিমিলাইজার থেকে @ স্টেট ভেরিয়েবলটি পরিবর্তন করা নীচের ত্রুটিটি ফেলে দেবে: থ্রেড 1: মারাত্মক ত্রুটি: ভিউ.বডি বাইরে স্টেট অ্যাক্সেস করা । এটি এড়াতে আপনার উচিত হয় @ স্টেটটি সরানো উচিত। যা উপলব্ধি করে কারণ অন্তর্ভুক্তডিসিমাল সত্যের উত্স নয়। এর মান পরিমাণ থেকে প্রাপ্ত। @ স্টেট অপসারণ করে তবে 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 { ... }
}

রব মায়োফ দ্বারা নির্দেশিত হিসাবে , আপনি স্টেট ভেরিয়েবল শুরু করতে $$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
-19

ঠিক আছে, এটি এক ধরণের অর্থপূর্ণ। @Stateভেরিয়েবলগুলির সত্যের উত্স উপস্থাপন করা উচিত। তবে আপনার ক্ষেত্রে আপনি সেই সত্যটিকে নকল করছেন, কারণ অন্তর্ভুক্ত ডেসিমালের মানটি আপনার সত্যের সত্য উত্স থেকে প্রাপ্ত হতে পারে যা পরিমাণ। আপনি দুটি বিকল্প আছে: 1. আপনি includeDecimal একটি প্রাইভেট Var (কোন @State), অথবা আরও ভাল 2. আপনি এটি একটি কম্পিউটেড সম্পত্তি থেকে এর মান বার করা করা amount। এই পরিমাণ, যদি পরিমাণ পরিবর্তন হয়, includeDecimalখুব কার্যকর। আপনি ভালো কি তা মেনে নেবে উচিত: private var includeDecimal: Bool { return round(amount)-amount > 0 }এবং অপসারণself.includeDecimal = ...
kontiki

হুম, আমার পরিবর্তন করতে সক্ষম হওয়া includeDecimalদরকার তাই ভিউতে @ স্টেট ভেরিয়েবল হিসাবে এটি দরকার। আমি সত্যিই এটির একটি প্রাথমিক মান দিয়ে শুরু করতে চাই
keegan3d

4
@ চলুন_আমি তৈরি করলাম আমি কেবল একবার তাদের সম্পূর্ণ দেখেছি, তবে ফরওয়ার্ডস বোতামটির জন্য god
শ্বরকে

4
সত্যিই চমৎকার ব্যাখ্যা, ধন্যবাদ। আমার মনে হয় এখন .valueএটির সাথে প্রতিস্থাপন করা হয়েছে .wrappedValue, উত্তরটি আপডেট করতে এবং বিটা বিকল্পগুলি অপসারণ করা ভাল হবে।
ব্যবহারকারী 1046037

11

আপনি বলেছেন (একটি মন্তব্যে) "আমার পরিবর্তন করতে সক্ষম হওয়া দরকার includeDecimal"। এটি পরিবর্তন মানে কি includeDecimal? আপনি স্পষ্টতই amount(আরম্ভের সময়ে) পূর্ণসংখ্যা কিনা তার ভিত্তিতে এটি শুরু করতে চান । ঠিক আছে. সুতরাং যদি includeDecimalহয় falseএবং তারপরে আপনি এটিতে পরিবর্তন করেন তবে কি হয় true? আপনি কি কোনওরকম বাধ্য হয়ে ততক্ষণে amountঅ-পূর্ণসংখ্যা হতে চলেছেন ?

যাই হোক, আপনি সংশোধন করতে পারবেন না includeDecimalinit। তবে আপনি এটির 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

2

এটি 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")
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.