সুইফটে প্রারম্ভিককরণের সময় কি ডিডসেটকে কল করার অনুমতি দেওয়া সম্ভব?


217

প্রশ্ন

অ্যাপলের ডক্স এটিকে নির্দিষ্ট করে:

যখন কোনও সম্পত্তি প্রথম শুরু করা হয় তখন উইলসেট এবং ডেটসেট পর্যবেক্ষকদের ডাকা হয় না। এগুলি তখনই ডাকা হয় যখন সম্পত্তির মান সূচনা প্রসঙ্গে বাইরে সেট করা থাকে।

আরম্ভের সময় এগুলি জোর করে বলা কি সম্ভব?

কেন?

ধরা যাক আমার এই ক্লাস আছে

class SomeClass {
    var someProperty: AnyObject {
        didSet {
            doStuff()
        }
    }

    init(someProperty: AnyObject) {
        self.someProperty = someProperty
        doStuff()
    }

    func doStuff() {
        // do stuff now that someProperty is set
    }
}

doStuffপ্রসেসিং কলগুলি আরও সংক্ষিপ্ততর করার জন্য আমি পদ্ধতিটি তৈরি করেছি , তবে আমি কেবল didSetফাংশনের মধ্যে থাকা সম্পত্তিটি প্রক্রিয়া করব । আরম্ভের সময় এই কল করতে বাধ্য করার কোনও উপায় আছে কি?

হালনাগাদ

আমি ঠিক করেছি আমার ক্লাসের জন্য সুবিধামত অন্তর্নিদীকরণ অপসারণ এবং প্রারম্ভিককরণের পরে আপনাকে সম্পত্তি সেট করতে বাধ্য করব। এটি আমাকে জানার অনুমতি দেয় didSetসর্বদা ডাকা হবে। এটি সামগ্রিকভাবে আরও ভাল কিনা তা আমি স্থির করি নি, তবে এটি আমার পরিস্থিতির পক্ষে ভাল।


এটি "দ্রুত এটি কীভাবে কাজ করে তা মেনে নেওয়ার জন্য" সত্যই এটি সর্বোত্তম। আপনি যদি ভেরির স্টেটমেন্টে একটি ইনলাইন ইনিশিয়ালাইজেশন মান রাখেন তবে অবশ্যই এটি "ডিডসেট" কল করে না। এজন্যই "init ()" পরিস্থিতিকে অবশ্যই "ডডসেট" কল করতে হবে না। এটা সব বোঝা যায়।
ফ্যাটি

@ লোগান প্রশ্নটিই আমার প্রশ্নের উত্তর দিয়েছে;) ধন্যবাদ!
আমিরআর

2
আপনি যদি deferconvenience init(someProperty: AnyObject) { self.init() defer { self.someProperty = someProperty }
সুবিধাম আরম্ভকারীটি

উত্তর:


100

একটি নিজস্ব সেট-পদ্ধতি তৈরি করুন এবং এটি আপনার init-পদ্ধতিতে ব্যবহার করুন:

class SomeClass {
    var someProperty: AnyObject! {
        didSet {
            //do some Stuff
        }
    }

    init(someProperty: AnyObject) {
        setSomeProperty(someProperty)
    }

    func setSomeProperty(newValue:AnyObject) {
        self.someProperty = newValue
    }
}

somePropertyপ্রকার হিসাবে ঘোষণা করে : AnyObject!(একটি স্পষ্টভাবে মোড়কযুক্ত optionচ্ছিক), আপনি somePropertyসেট না করেই নিজেকে পুরোপুরি আরম্ভ করার অনুমতি দিন । আপনি যখন কল করবেন তখন এর setSomeProperty(someProperty)সমতুল্য কল করবেন self.setSomeProperty(someProperty)। সাধারণত আপনি এটি করতে সক্ষম হবেন না কারণ স্ব সম্পূর্ণরূপে আরম্ভ করা হয়নি। যেহেতু somePropertyপ্রারম্ভিককরণের প্রয়োজন নেই এবং আপনি নিজের উপর নির্ভরশীল কোনও পদ্ধতি কল করছেন, তাই সুইফট সূচনা প্রবন্ধটি ছেড়ে দেয় এবং ডেটসেট চলবে।


3
এটি কেন আত্মপরিচয় থেকে পৃথক হবে? ইনপিতে থাকা নিউ ভ্যালু থেকে? আপনি একটি ওয়ার্কিং পরীক্ষার কেস পেয়েছেন?
মিমি মিমি মিমি

2
কেন এটি কাজ করে তা জানেন না - তবে তা করে। সরাসরি init () এর মধ্যে নতুন মানটি নির্ধারণ করে - পদ্ধতিটি ডিডসেট () কল করে না - তবে প্রদত্ত পদ্ধতিটি সেটসোমপ্রোপার্টি () ব্যবহার করে।
অলিভার

50
আমি মনে করি আমি জানি এখানে কী ঘটছে। somePropertyপ্রকার হিসাবে ঘোষণা করে : AnyObject!(একটি স্পষ্টতভাবে মোড়কযুক্ত optionচ্ছিক), আপনি সেট selfনা করে পুরোপুরি আরম্ভ করার অনুমতি দিন someProperty। আপনি যখন কল করবেন তখন এর setSomeProperty(someProperty)সমতুল্য কল করবেন self.setSomeProperty(someProperty)। সাধারণত আপনি এটি করতে সক্ষম হবেন না কারণ selfপুরোপুরি আরম্ভ করা হয়নি। যেহেতু somePropertyপ্রারম্ভিককরণের প্রয়োজন নেই এবং আপনি নির্ভরশীল কোনও পদ্ধতিতে কল করছেন তাই selfসুইফট সূচনা প্রবন্ধটি ছেড়ে যায় এবং didSetচলবে।
লোগান

3
দেখে মনে হচ্ছে এমন কিছু যা প্রকৃত আরম্ভের বাইরে সেট করা আছে () ডিডসেট কল করে। আক্ষরিক যে কোনও কিছু সেট init() { *HERE* }করা নেই ডেটসেট কল করবে। এই প্রশ্নের জন্য দুর্দান্ত তবে কিছু মান সেট করতে একটি গৌণ ফাংশন ব্যবহার করা ডডসেটকে ডেকে আনে। আপনি যদি সেটার ফাংশনটি পুনরায় ব্যবহার করতে চান তবে দুর্দান্ত নয়।
ডাব্লুসিবিয়ার্ন

4
@ মারাত্মকভাবে মার্ক করুন, সুইফটে সাধারণ জ্ঞান বা যুক্তি প্রয়োগের চেষ্টা করা কেবল অযৌক্তিক। তবে আপনি আপভোটগুলিতে বিশ্বাস রাখতে পারেন বা এটি নিজে চেষ্টা করতে পারেন। আমি সবেমাত্র করেছি এবং এটি কাজ করে। এবং হ্যাঁ, এটি মোটেই বোঝা যায় না।
ড্যান রোজনস্টার্ক

305

আপনি ব্যবহার করেন তাহলে deferএকটি ভেতরে সূচনাকারী কোনো ঐচ্ছিক বৈশিষ্ট্য বা আরও আপডেট অ ঐচ্ছিক বৈশিষ্ট্য যে আপনি ইতিমধ্যে সক্রিয়া করেছি আপডেট করার জন্য ও পরে যদি আপনি কোন ডেকেছে super.init()পদ্ধতি, তারপর আপনার willSet, didSetইত্যাদি ডাকা হবে। আপনি সঠিক জায়গায় কলিংয়ের ট্র্যাক রাখতে হবে এমন আলাদা পদ্ধতি প্রয়োগের চেয়ে এটি আরও সুবিধাজনক বলে মনে করি।

উদাহরণ স্বরূপ:

public class MyNewType: NSObject {

    public var myRequiredField:Int

    public var myOptionalField:Float? {
        willSet {
            if let newValue = newValue {
                print("I'm going to change to \(newValue)")
            }
        }
        didSet {
            if let myOptionalField = self.myOptionalField {
                print("Now I'm \(myOptionalField)")
            }
        }
    }

    override public init() {
        self.myRequiredField = 1

        super.init()

        // Non-defered
        self.myOptionalField = 6.28

        // Defered
        defer {
            self.myOptionalField = 3.14
        }
    }
}

ফলন হবে:

I'm going to change to 3.14
Now I'm 3.14

6
ছদ্মবেশী ছোট্ট কৌশল, আমি এটি পছন্দ করি ... যদিও সুইফটের অদ্ভুত স্পর্শ।
ক্রিস হ্যাটন

4
গ্রেট। আপনি ব্যবহারের আরেকটি দরকারী কেস খুঁজে পেয়েছেন defer। ধন্যবাদ।
রায়ান

1
স্থগিতের দুর্দান্ত ব্যবহার! আশা করি আমি আপনাকে একাধিক উত্সাহ দিতে পারতাম।
খ্রিস্টান শ্নর

3
খুব ইন্টারেস্টিং .. আমি এর আগে এর আগে মুলতুবি কখনও ব্যবহার করতে দেখিনি। এটি সুস্পষ্ট এবং কাজ করে।
এবিকিস

তবে আপনি দুবার মাইওপশনালফিল্ড সেট করেছেন যা পারফরম্যান্সের দিক থেকে দুর্দান্ত নয়। ভারী হিসাব যদি হয়?
ইয়াকিভ কোভালস্কি

77

অলিভারের উত্তরের ভিন্নতা হিসাবে, আপনি কোনও বন্ধে লাইনগুলি মোড়ানো করতে পারেন। উদাহরণ:

class Classy {

    var foo: Int! { didSet { doStuff() } }

    init( foo: Int ) {
        // closure invokes didSet
        ({ self.foo = foo })()
    }

}

সম্পাদনা: ব্রায়ান ওয়েস্টফালের উত্তরটি ভাল ইমো। তার সম্পর্কে দুর্দান্ত বিষয়টি হ'ল এটি অভিপ্রায়টির ইঙ্গিত দেয়।


2
এটি চালাক এবং অপ্রয়োজনীয় পদ্ধতিতে শ্রেণিকে কলুষিত করে না।
পয়েন্ট

দুর্দান্ত উত্তর, ধন্যবাদ! উল্লেখযোগ্য যে লক্ষণীয় যে সুইফট ২.২ এ আপনাকে বন্ধনটি সর্বদা বন্ধন মোড়ানো দরকার।
সর্বাধিক

@Max চিয়ার্স, নমুনা এখন ডান বন্ধনী অন্তর্ভুক্ত
original_username

2
চতুর উত্তর! একটি দ্রষ্টব্য: যদি আপনার শ্রেণি অন্য কোনও কিছুর সাবক্লাস হয় তবে আপনাকে ({self.foo = foo}) ()
কেসিস্ট্রিক্স

1
@ হালং, আমি অন্য কোনও কিছুর চেয়ে ভবিষ্যতে ভেঙে যাওয়ার সম্ভাবনা অনুভব করি না, তবে এখনও সমস্যা রয়েছে যে কোডটি মন্তব্য না করে এটি কী করে তা খুব পরিষ্কার নয়। কমপক্ষে ব্রায়ানের "মুলতুবি" উত্তর পাঠককে একটি ইঙ্গিত দেয় যা আমরা প্রাথমিককরণের পরে কোডটি সম্পাদন করতে চাই।
original_username

10

আমারও একই সমস্যা ছিল এবং এটি আমার পক্ষে কাজ করে

class SomeClass {
    var someProperty: AnyObject {
        didSet {
            doStuff()
        }
    }

    init(someProperty: AnyObject) {
        defer { self.someProperty = someProperty }
    }

    func doStuff() {
        // do stuff now that someProperty is set
    }
}

আপনি এটি কোথায় পেয়েছেন?
ভ্যানিয়া

3
এই পদ্ধতির আর কাজ করে না। সংকলকটি দুটি ত্রুটি নিক্ষেপ করে: - সমস্ত সঞ্চিত বৈশিষ্ট্য সূচনা করার আগে মেথড কলটিতে 'সেল্ফ' ব্যবহার করা হয় all
এডওয়ার্ড বি

আপনি ঠিক বলেছেন কিন্তু একটি কর্মক্ষেত্র আছে। আপনাকে কেবল কিছু প্রপার্টিটিকে অন্তর্ভুক্ত আনরোপড বা alচ্ছিক হিসাবে ঘোষণা করতে হবে এবং ব্যর্থতা এড়ানোর জন্য এটি শূন্য কোয়েলেসিংয়ের সাথে ডিফল্ট মান হিসাবে সরবরাহ করবে। tldr; কিছুপ্রোপার্টি অবশ্যই একটি alচ্ছিক ধরণের হতে হবে
চিহ্নিত করুন

2

আপনি যদি একটি সাবক্লাসে এটি করেন তবে এটি কাজ করে

class Base {

  var someProperty: AnyObject {
    didSet {
      doStuff()
    }
  }

  required init() {
    someProperty = "hello"
  }

  func doStuff() {
    print(someProperty)
  }
}

class SomeClass: Base {

  required init() {
    super.init()

    someProperty = "hello"
  }
}

let a = Base()
let b = SomeClass()

ইন aউদাহরণস্বরূপ, didSetআলোড়ন করা হয় না। তবে bউদাহরণস্বরূপ, didSetট্রিগার করা হয়েছে, কারণ এটি সাবক্লাসে রয়েছে। এটি initialization contextসত্যিকারের অর্থ সহ কিছু করতে হবে , এক্ষেত্রে বিষয়টি superclassতার যত্ন নিয়েছে


1

যদিও এটি কোনও সমাধান নয়, এটির বিকল্প পদ্ধতিতে শ্রেণি নির্মাতা ব্যবহার করা হবে:

class SomeClass {
    var someProperty: AnyObject {
        didSet {
            // do stuff
        }
    }

    class func createInstance(someProperty: AnyObject) -> SomeClass {
        let instance = SomeClass() 
        instance.someProperty = someProperty
        return instance
    }  
}

1
এই সমাধানটির আপনার বিকল্পের পরিবর্তন প্রয়োজন somePropertyকারণ এটি সূচনা করার সময় এটির কোনও মূল্য দেয় না।
মিক ম্যাককালাম

1

আপনার সুপারক্লাসে উপলব্ধ কোনও সংস্থার জন্য আপনি যেখানে অনুরোধ করতে willSetবা তার didSetভিতরে যেতে চান সেখানে আপনি initকেবল নিজের সুপার সম্পত্তি সরাসরি অর্পণ করতে পারেন:

override init(frame: CGRect) {
    super.init(frame: frame)
    // this will call `willSet` and `didSet`
    someProperty = super.someProperty
}

নোট করুন যে একটি ক্লার্স সহ চার্লিজম সলিউশন সে ক্ষেত্রে সর্বদা খুব কার্যকর হবে work সুতরাং আমার সমাধানটি কেবল একটি বিকল্প।


-1

আপনি এটি আপত্তিজনকভাবে সমাধান করতে পারেন:

class SomeClass {
    private var _someProperty: AnyObject!
    var someProperty: AnyObject{
        get{
            return _someProperty
        }
        set{
            _someProperty = newValue
            doStuff()
        }
    }
    init(someProperty: AnyObject) {
        self.someProperty = someProperty
        doStuff()
    }

    func doStuff() {
        // do stuff now that someProperty is set
    }
}

1
হাই @ আইশিলভ, আমি মনে করি না যে এটি প্রযুক্তিগতভাবে যেহেতু আমি প্রত্যাশা করেছিলাম তা সত্যিই সমাধান করে, যখন আপনি কল করবেন যখন আপনি self.somePropertyআরম্ভের সুযোগ ছেড়ে যাচ্ছেন। আমি বিশ্বাস করি একই কাজটি করে কাজটি করা সম্ভব হয়েছিল var someProperty: AnyObject! = nil { didSet { ... } }। তবুও, কেউ কেউ এটি প্রায় কাজ হিসাবে প্রশংসা করতে পারে, সংযোজনের জন্য ধন্যবাদ
লোগান

@ লোগান না, এটি কার্যকর হবে না। didSet টি পুরোপুরি উপেক্ষা করা হবে ()।
yshilov
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.