সুইফটে একটি প্রাপ্য আরম্ভকারীকে কার্যকর করার সেরা অনুশীলন


100

নিম্নলিখিত কোড সহ আমি একটি সাধারণ মডেল শ্রেণি সংজ্ঞায়িত করার চেষ্টা করি এবং এটি অনুপলব্ধ আরম্ভকারী, যা প্যারামিটার হিসাবে একটি (জেসন-) অভিধান গ্রহণ করে। প্রাথমিক nilনামটি যদি জেসসনটিতে ব্যবহারকারীর নাম সংজ্ঞায়িত না করা হয় তবে প্রারম্ভিকটি ফিরিয়ে আনতে হবে।

1. কোডটি সংকলন করে না কেন? ত্রুটি বার্তাটি বলে:

কোনও ক্লাস ইনস্ট্যান্সের সমস্ত সঞ্চিত বৈশিষ্ট্য কোনও ইনিশিয়ালাইজারের কাছ থেকে শূন্যের আগে ফিরে আসতে হবে initial

এটা বোঝা যায় না। আমি যখন ফেরত দেওয়ার পরিকল্পনা করছি তখন কেন আমি এই সম্পত্তিগুলি শুরু করব nil?

২) আমার দৃষ্টিভঙ্গিটি কি সঠিক বা আমার লক্ষ্য অর্জনের জন্য অন্যান্য ধারণা বা সাধারণ নিদর্শন থাকবে?

class User: NSObject {

    let userName: String
    let isSuperUser: Bool = false
    let someDetails: [String]?

    init?(dictionary: NSDictionary) {
        if let value: String = dictionary["user_name"] as? String {
            userName = value
        }
        else {
           return nil
        }

        if let value: Bool = dictionary["super_user"] as? Bool {
            isSuperUser = value
        }

        someDetails = dictionary["some_details"] as? Array

        super.init()
    }
}

আমার অনুরূপ সমস্যা ছিল, আমার সাথে আমি এই সিদ্ধান্তে পৌঁছেছি যে প্রতিটি অভিধানের মান আশা করা উচিত এবং তাই আমি মানগুলিকে আনারপেট করতে বাধ্য করি। সম্পত্তি যদি সেখানে না থাকে তবে আমি বাগটি ধরতে সক্ষম হব। অতিরিক্তভাবে, আমি canSetCalculablePropertiesআমার ইনিশিয়ালকে এমন বৈশিষ্ট্য গণনা করতে সক্ষম করে যা ফ্লাইতে তৈরি করা যায় না বা তৈরি করা যায় না। উদাহরণস্বরূপ, যদি কোনও dateCreatedকী অনুপস্থিত থাকে এবং canSetCalculablePropertiesপ্যারামিটারটি সত্য বলে আমি ফ্লাইতে সম্পত্তি সেট করতে পারি তবে আমি কেবল এটি বর্তমান তারিখটিতে সেট করেছি।
অ্যাডাম কার্টার

উত্তর:


71

আপডেট করুন: থেকে সুইফট 2.2 লগিন পরিবর্তন করুন (মার্চ 21, 2016 মুক্তি):

অনুপযুক্ত বা থ্রোিং হিসাবে ঘোষিত মনোনীত শ্রেণি প্রারম্ভিকরা অবজেক্টটি সম্পূর্ণরূপে আরম্ভ করার আগে যথাক্রমে শূন্যতা বা ত্রুটি নিক্ষেপ করতে পারে।


সুইফট ২.১ এবং তার আগের:

অ্যাপলের ডকুমেন্টেশন (এবং আপনার সংকলক ত্রুটি) অনুসারে, কোনও ক্লাসে nilকোনও প্রাপ্য আরম্ভকারী থেকে ফিরে আসার আগে অবশ্যই তার সমস্ত সঞ্চিত বৈশিষ্ট্য শুরু করতে হবে:

ক্লাসগুলির জন্য, তবে একটি অনুপযুক্ত আরম্ভকারী কেবল তখনই শ্রেণীর দ্বারা প্রবর্তিত সমস্ত সঞ্চিত সম্পত্তি প্রাথমিক মান হিসাবে সেট করা হয়ে যায় এবং যে কোনও আরম্ভকারী প্রতিনিধি সংঘটিত হওয়ার পরে কেবল একটি সূচনা ব্যর্থতা ট্রিগার করতে পারে।

দ্রষ্টব্য: এটি কাঠামোগুলি এবং গণনার জন্য আসলে কাজ করে, কেবল ক্লাস নয় not

আদ্যক্ষর ব্যর্থ হওয়ার আগে আরম্ভ করা যায় না এমন সঞ্চিত বৈশিষ্ট্যগুলি হ্যান্ডেল করার প্রস্তাবিত উপায় হ'ল এগুলিকে স্পষ্টতভাবে মোড়কযুক্ত বিকল্প হিসাবে ঘোষণা করা।

দস্তাবেজ থেকে উদাহরণ:

class Product {
    let name: String!
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}

উপরের উদাহরণে, পণ্য শ্রেণীর নাম বৈশিষ্ট্যটি একটি স্পষ্টভাবে মোড়কযুক্ত alচ্ছিক স্ট্রিং প্রকার (স্ট্রিং!) হিসাবে সংজ্ঞায়িত করা হয়। কারণ এটি একটি optionচ্ছিক প্রকারের, এর অর্থ এটি হ'ল নামের শুরুতে শুরুর আগে একটি নির্দিষ্ট মান নির্ধারিত হওয়ার আগে শূন্যের একটি ডিফল্ট মান থাকে। পরিবর্তে শূন্যের এই ডিফল্ট মানটির অর্থ হ'ল পণ্য শ্রেণীর দ্বারা প্রবর্তিত সমস্ত বৈশিষ্ট্যের একটি বৈধ প্রাথমিক মান রয়েছে। ফলস্বরূপ, প্রডাক্টের জন্য অনুপলব্ধ আরম্ভকারী আরম্ভকারীর মধ্যে নামের বৈশিষ্ট্যের একটি নির্দিষ্ট মান নির্ধারিত করার আগে, খালি স্ট্রিংটি পাস করা হয় তবে আরম্ভকারীটির শুরুতে একটি সূচনা ব্যর্থতা ট্রিগার করতে পারে।

আপনার ক্ষেত্রে, তবে কেবল userNameহিসাবে সংজ্ঞায়িত করা String!সংকলন ত্রুটিটি ঠিক করে না কারণ আপনার বেস ক্লাসে বৈশিষ্ট্যগুলি আরম্ভ করার বিষয়ে আপনাকে এখনও চিন্তা করতে হবে NSObject,। ভাগ্যক্রমে, এ userNameহিসাবে সংজ্ঞায়িত করে String!, আপনি আসলে আপনার super.init()আগে কল করতে পারেন return nilযা আপনার NSObjectবেস ক্লাস শুরু করবে এবং সংকলনের ত্রুটিটি ঠিক করবে।

class User: NSObject {

    let userName: String!
    let isSuperUser: Bool = false
    let someDetails: [String]?

    init?(dictionary: NSDictionary) {
        super.init()

        if let value = dictionary["user_name"] as? String {
            self.userName = value
        }
        else {
            return nil
        }

        if let value: Bool = dictionary["super_user"] as? Bool {
            self.isSuperUser = value
        }

        self.someDetails = dictionary["some_details"] as? Array
    }
}

1
আপনাকে অনেক ধন্যবাদ শুধুমাত্র সঠিক নয়, তবে এটিও ভালভাবে ব্যাখ্যা করেছেন
কাই হাপম্যান

9
সুইফট ১.২ এ, ডক্সের উদাহরণ থেকে একটি ত্রুটি হয়েছে "একটি প্রাথমিক শ্রেণীর উদাহরণের সমস্ত সঞ্চিত বৈশিষ্ট্য একটি প্রাথমিককরণ থেকে শূন্যস্থান ফিরে পাওয়ার আগে আরম্ভ করা উচিত"
জেফ্রি

2
@ জেফ্রি এটি সঠিক, ডকুমেন্টেশন ( Productক্লাস) থেকে প্রাপ্ত উদাহরণগুলি একটি নির্দিষ্ট মান নির্ধারণের আগে সূচনা ব্যর্থতা ট্রিগার করতে পারে না, যদিও ডকস এটি করতে পারে তা সত্ত্বেও। দস্তাবেজগুলি সর্বশেষতম সুইফ্ট সংস্করণের সাথে সিঙ্ক নয়। varপরিবর্তে এখনই এটি করার পরামর্শ দেওয়া হচ্ছে letউৎস: ক্রিস Lattner
আরজান

1
ডকুমেন্টেশনের কোডের এই অংশটি কিছুটা আলাদা আছে: আপনি প্রথমে সম্পত্তিটি সেট করেন এবং তারপরে এটি উপস্থিত কিনা তা পরীক্ষা করে দেখুন। "ক্লাসের জন্য প্রাপ্য আরম্ভকারী", "দ্য সুইফ্ট প্রোগ্রামিং ল্যাঙ্গুয়েজ" দেখুন। `` `শ্রেণি পণ্য name নাম দিন: স্ট্রিং! ? Init (নাম: স্ট্রিং) {self.name = যদি name.isEmpty {ফিরতি শূন্য} নাম}} ``
মিশা Karpenko

আমি এটি অ্যাপল ডক্সেও পড়েছি তবে কেন এটি প্রয়োজন হবে তা দেখতে আমি ব্যর্থ। একটি ব্যর্থতা যাই হোক না কেন শূন্য ফিরে মানে, সম্পত্তি কি আরম্ভ করা হয়েছে কিনা তা পরে কি ব্যাপার?
আল্পার

132

এটা বোঝা যায় না। যখন আমি শূন্য ফেরত দেওয়ার পরিকল্পনা করছি তখন কেন আমি এই বৈশিষ্ট্যগুলি শুরু করব?

ক্রিস ল্যাটারের মতে এটি একটি বাগ। এখানে তিনি যা বলেছেন:

এটি রিলিজ নোটগুলিতে নথিভুক্ত সুইফট 1.1 সংকলকটিতে একটি বাস্তবায়ন সীমাবদ্ধতা। সংকলক বর্তমানে সমস্ত ক্ষেত্রে আংশিকভাবে প্রাথমিক শ্রেণিগুলি ধ্বংস করতে অক্ষম, সুতরাং এটি এমন পরিস্থিতিতে তৈরি হওয়াটিকে অস্বীকার করে। আমরা এটিকে কোনও বৈশিষ্ট্য নয়, ভবিষ্যতের রিলিজগুলিতে স্থির করা বাগ হিসাবে বিবেচনা করি।

উৎস

সম্পাদনা করুন:

তাই সুইফট এখন ওপেন সোর্স এবং এই চেঞ্জলগ অনুসারে এটি এখন সুইফট ২.২ এর স্ন্যাপশটে স্থির করা হয়েছে

অনুপযুক্ত বা থ্রোিং হিসাবে ঘোষিত মনোনীত শ্রেণি প্রারম্ভিকরা অবজেক্টটি সম্পূর্ণরূপে আরম্ভ করার আগে যথাক্রমে শূন্যতা বা ত্রুটি নিক্ষেপ করতে পারে।


2
আমার বক্তব্যটি সম্বোধন করার জন্য ধন্যবাদ যে প্রপার্টিগুলির আরম্ভ করার ধারণাটি যে কোনও প্রয়োজন হবে না তা খুব যুক্তিসঙ্গত বলে মনে হয় না। এবং একটি উত্স ভাগ করে নেওয়ার জন্য +1, যা প্রমাণ করে যে ক্রিস ল্যাটনার আমার মতো অনুভব করে;)।
কাই হুপম্যান

22
এফওয়াইআই: "প্রকৃতপক্ষে। এটি এখনও এমন কিছু যা আমরা উন্নত করতে চাই, তবে সুইফট ১.২ এর জন্য কাটটি তৈরি করিনি"। - ক্রিস
ল্যাটনার

14
এফওয়াইআই: সুইফট ২.০ বিটা ২-তে এটি এখনও একটি সমস্যা এবং এটি একটি ইনিশিয়ালাইজারেরও সমস্যা যা ছোঁড়ে।
অরণসৌরাস

7

আমি মিক এস এর উত্তরটি অ্যাপলের সুপারিশ হিসাবে গ্রহণ করেছি, তবে আমি এটি সর্বোত্তম অনুশীলন বলে মনে করি না। একটি শক্তিশালী টাইপ সিস্টেমের পুরো পয়েন্টটি সময় সংকলন করতে রানটাইম ত্রুটিগুলি সরানো হয়। এই "সমাধান" সেই উদ্দেশ্যকে পরাস্ত করে। আইএমএইচও, আরও ভাল হবে আরও এগিয়ে গিয়ে ব্যবহারকারী ""নামটি আরম্ভ করুন এবং তারপরে সুপার.নাইট () এর পরে এটি পরীক্ষা করুন। যদি ফাঁকা ব্যবহারকারীর নাম অনুমোদিত হয় তবে একটি পতাকা সেট করুন।

class User: NSObject {
    let userName: String = ""
    let isSuperUser: Bool = false
    let someDetails: [String]?

    init?(dictionary: [String: AnyObject]) {
        if let user_name = dictionary["user_name"] as? String {
            userName = user_name
        }

        if let value: Bool = dictionary["super_user"] as? Bool {
            isSuperUser = value
        }

        someDetails = dictionary["some_details"] as? Array

        super.init()

        if userName.isEmpty {
            return nil
        }
    }
}

ধন্যবাদ, তবে মাইকের উত্তর দিয়ে শক্তিশালী টাইপ সিস্টেমগুলির ধারণাগুলি কীভাবে দূষিত হয়েছে তা আমি দেখতে পাই না। প্রাথমিকভাবে শূন্যের পরিবর্তে প্রাথমিক মান সেট করা আছে তার পার্থক্যের সাথে আপনি সমস্তই একই সমাধান উপস্থাপন করুন। তদুপরি, আপনি কোডটি ব্যবহারকারীর নাম হিসাবে ব্যবহার করতে দূরে সরে গেছেন (যা সম্ভবত একাডেমিকভাবে মনে হতে পারে, তবে কমপক্ষে এটি
জসন

2
পর্যালোচনা করার পরে, আমি দেখতে পাচ্ছি যে আপনি ঠিক বলেছেন, তবে কেবলমাত্র ব্যবহারকারী নামটি ধ্রুবক। যদি এটি পরিবর্তনশীল হয় তবে গ্রহণযোগ্য উত্তরটি আমার চেয়ে খারাপ হবে কারণ ব্যবহারকারী নামটি পরে শূন্য করা যেতে পারে।
ড্যানিয়েল টি।

আমি এই উত্তর পছন্দ। @ কাইহাপম্যান, আপনি যদি খালি ব্যবহারকারীর নাম অনুমোদন করতে চান তবে আপনার কাছে একটি সাধারণ বুলের প্রয়োজনীয়তা রিটারননিলও থাকতে পারে। যদি অভিধানে মানটি না উপস্থিত থাকে, তবে প্রয়োজনীয়তাগুলি রিটারননিলকে সত্যতে সেট করুন এবং ব্যবহারকারী নামকে যা কিছুতে সেট করুন। সুপার ইন্ডিআইটি () এর পরে, প্রয়োজনীয়তাগুলি পুনর্বার নীল পরীক্ষা করুন এবং প্রয়োজনে শূন্য করুন।
রিচার্ড ভেনেবল

6

সীমাবদ্ধতা রোধ করার আরেকটি উপায় হ'ল সূচনা করার জন্য শ্রেণি-ফাংশনগুলির সাথে কাজ করা। আপনি এমনকি এই ক্রিয়াকলাপটি কোনও এক্সটেনশনে স্থানান্তর করতে চাইতে পারেন:

class User: NSObject {

    let username: String
    let isSuperUser: Bool
    let someDetails: [String]?

    init(userName: String, isSuperUser: Bool, someDetails: [String]?) {

         self.userName = userName
         self.isSuperUser = isSuperUser
         self.someDetails = someDetails

         super.init()
    }
}

extension User {

    class func fromDictionary(dictionary: NSDictionary) -> User? {

        if let username: String = dictionary["user_name"] as? String {

            let isSuperUser = (dictionary["super_user"] as? Bool) ?? false
            let someDetails = dictionary["some_details"] as? [String]

            return User(username: username, isSuperUser: isSuperUser, someDetails: someDetails)
        }

        return nil
    }
}

এটি ব্যবহার করা হয়ে উঠবে:

if let user = User.fromDictionary(someDict) {

     // Party hard
}

1
আমি এটি পছন্দ করি; আমি কনস্ট্রাক্টররা তাদের পছন্দসই বিষয়ে স্বচ্ছ হতে পছন্দ করি এবং একটি অভিধানে পাস করা খুব অস্বচ্ছ।
বেন লেগজিও

3

যদিও সুইফট ২.২ প্রকাশিত হয়েছে এবং ইনিশিয়ালাইজার ব্যর্থ হওয়ার আগে আপনাকে আর পুরোপুরি আরম্ভ করতে হবে না, আপনি https://bugs.swift.org/browse/SR-704 স্থির না হওয়া পর্যন্ত আপনার ঘোড়াগুলি ধরে রাখা দরকার ।


1

আমি এটি সুইফট ১.২ এ সম্পন্ন করতে পেরেছি

কিছু শর্ত রয়েছে:

  • প্রয়োজনীয় বৈশিষ্ট্যগুলি সুস্পষ্টভাবে মোড়কযুক্ত বিকল্প হিসাবে ঘোষণা করা উচিত
  • আপনার প্রয়োজনীয় বৈশিষ্ট্যগুলিতে একবারে একটি মূল্য নির্ধারণ করুন। এই মান শূন্য হতে পারে।
  • তারপরে যদি আপনার ক্লাসটি অন্য শ্রেণি থেকে উত্তরাধিকার সূত্রে লিখিত হয় তবে সুপারিনাইটকে কল করুন।
  • আপনার সমস্ত প্রয়োজনীয় বৈশিষ্ট্যগুলিকে একটি মান নির্ধারিত হওয়ার পরে , তাদের মানটি প্রত্যাশার মতো কিনা তা পরীক্ষা করুন। যদি না হয়, শূন্য ফিরে।

উদাহরণ:

class ClassName: NSObject {

    let property: String!

    init?(propertyValue: String?) {

        self.property = propertyValue

        super.init()

        if self.property == nil {
            return nil
        }
    }
}

0

একটি মান ধরণের (যা একটি কাঠামো বা গণনা) জন্য একটি অনুপযুক্ত আরম্ভকারী তার ইনিশিয়ালাইজার প্রয়োগের মধ্যে যে কোনও সময়ে একটি সূচনা ব্যর্থতা ট্রিগার করতে পারে

ক্লাসগুলির জন্য, তবে একটি অনুপযুক্ত আরম্ভকারী কেবল তখনই শ্রেণীর দ্বারা প্রবর্তিত সমস্ত সঞ্চিত সম্পত্তি প্রাথমিক মান হিসাবে সেট করা হয়ে যায় এবং যে কোনও আরম্ভকারী প্রতিনিধি সংঘটিত হওয়ার পরে কেবল একটি সূচনা ব্যর্থতা ট্রিগার করতে পারে।

এর উত্স: অ্যাপল ইনক। “ দ্য সুইফ্ট প্রোগ্রামিং ভাষা। ”আইবুকস। https://itun.es/sg/jEUH0.l


0

আপনি সুবিধাপূর্ণ ডিআইএম ব্যবহার করতে পারেন :

class User: NSObject {
    let userName: String
    let isSuperUser: Bool = false
    let someDetails: [String]?

    init(userName: String, isSuperUser: Bool, someDetails: [String]?) {
        self.userName = userName
        self.isSuperUser = isSuperUser
        self.someDetails = someDetails
    }     

    convenience init? (dict: NSDictionary) {            
       guard let userName = dictionary["user_name"] as? String else { return nil }
       guard let isSuperUser = dictionary["super_user"] as? Bool else { return nil }
       guard let someDetails = dictionary["some_details"] as? [String] else { return nil }

       self.init(userName: userName, isSuperUser: isSuperUser, someDetails: someDetails)
    } 
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.