स्विफ्ट, स्पष्ट उदाहरणों में सुविधा init बनाम init के बीच अंतर क्या है, बेहतर है


82

मुझे दोनों के बीच के अंतर या उद्देश्य को समझने में परेशानी हो रही है convenience init


क्या आपने द स्विफ्ट प्रोग्रामिंग लैंग्वेज बुक के इनिशियलाइज़ेशन सेक्शन को पढ़ा है ? वास्तव में आपका भ्रम क्या है?
रैमेडी

1
एसओ में पहले से ही उत्तर उपलब्ध हैं। कृपया देखें - stackoverflow.com/questions/30896231/…
संतोष

जवाबों:


105

मानक init:

नामित इनिशियलाइज़र एक क्लास के लिए प्राइमरी इनिशियलाइज़र हैं। एक नामित इनिशियलाइज़र उस वर्ग द्वारा शुरू की गई सभी संपत्तियों को पूरी तरह से इनिशियलाइज़ करता है और सुपरक्लास चेन को इनिशियलाइज़ेशन प्रक्रिया जारी रखने के लिए एक उपयुक्त सुपरक्लास इनिशलाइज़र कहता है।

convenience init:

सुविधा इनिशियलाइज़र माध्यमिक हैं, एक वर्ग के लिए इनिशियलाइज़र का समर्थन करते हैं। आप एक सुविधा इनिशियलाइज़र को एक ही वर्ग से निर्दिष्ट इनिशियलाइज़र के रूप में परिभाषित करने के लिए सुविधा इनिशियलाइज़र के रूप में परिभाषित कर सकते हैं, जिसमें कुछ इनिशियलाइज़र मापदंडों को डिफ़ॉल्ट मानों पर सेट किया गया है। आप विशिष्ट उपयोग के मामले या इनपुट मूल्य प्रकार के लिए उस वर्ग का उदाहरण बनाने के लिए एक सुविधा इनिशियलाइज़र को भी परिभाषित कर सकते हैं।

स्विफ्ट डॉक्यूमेंटेशन के अनुसार

संक्षेप में, इसका मतलब यह है कि आप एक नामित इनिशियलाइज़र को कॉल करने के लिए एक सुविधा इनिशियलाइज़र का उपयोग कर सकते हैं जो तेजी से और अधिक "सुविधाजनक" है। इसलिए सुविधा इनिशियलाइज़र self.initके लिए super.initआपको निर्दिष्ट इनिशियलाइज़र के ओवरराइड में देखने के बजाय इसके उपयोग की आवश्यकता होती है।

स्यूडोकोड उदाहरण:

init(param1, param2, param3, ... , paramN) {
     // code
}

// can call this initializer and only enter one parameter,
// set the rest as defaults
convenience init(myParamN) {
     self.init(defaultParam1, defaultParam2, defaultParam3, ... , myParamN)
}

कस्टम दृश्य बनाते समय और मुख्य रूप से चूक के साथ लंबे आरंभीकरण करने वाले ऐसे लोगों का उपयोग करता हूं। डॉक्स एक बेहतर काम करते हैं जो मैं समझा सकता हूं, उन्हें देखें!


73

सुविधा इनिशियलाइज़र का उपयोग तब किया जाता है जब आपके पास बहुत सारे गुणों के साथ कुछ वर्ग होता है जो इसे "दर्दनाक" के रूप में हमेशा सभी वैरिएबल्स के साथ बुद्धि को इनिशियलाइज़ करता है, इसलिए आप सुविधा इनिशियलाइज़र के साथ क्या करते हैं, यह है कि आप कुछ वैरिएबल्स को आरंभीकृत करने के लिए पास करते हैं ऑब्जेक्ट, और बाकी को एक डिफ़ॉल्ट मान के साथ असाइन करें। रे वेंडरलिच वेबसाइट पर एक बहुत अच्छा वीडियो है, यह सुनिश्चित नहीं है कि यह मुफ़्त है या नहीं क्योंकि मेरे पास एक भुगतान किया गया खाता है। यहां एक उदाहरण है जहां आप देख सकते हैं कि मेरी वस्तु को उन सभी चर के साथ आरम्भ करने के बजाय मैं इसे एक शीर्षक दे रहा हूं।

struct Scene {
  var minutes = 0
}

class Movie {
  var title: String
  var author: String
  var date: Int
  var scenes: [Scene]

  init(title: String, author: String, date: Int) {
    self.title = title
    self.author = author
    self.date = date
    scenes = [Scene]()
  }

  convenience init(title:String) {
    self.init(title:title, author: "Unknown", date:2016)
  }

  func addPage(page: Scene) {
    scenes.append(page)
  }
}


var myMovie = Movie(title: "my title") // Using convenicence initializer
var otherMovie = Movie(title: "My Title", author: "My Author", date: 12) // Using a long normal initializer

4
अच्छा उदाहरण। इससे अवधारणा स्पष्ट हुई। धन्यवाद।
अर्जुन कालिदास

5
हम लेखक और दिनांक पैरामीटर के लिए डिफ़ॉल्ट मान के साथ init () भी कर सकते हैं जैसे init (शीर्षक: स्ट्रिंग, लेखक: स्ट्रिंग = "अज्ञात", दिनांक: Int = 2016) {self.title = शीर्षक self.author = लेखक स्वयं। date = तारीख के दृश्य = [दृश्य] ()} `तो फिर हमें सुविधा इनिशियलाइज़र की आवश्यकता क्यों है?
shripad20

@ shripad20 यहाँ एक ही सवाल। क्या आपने पाया कि हमें सुविधा का उपयोग क्यों करना है हालांकि हम एक और इनिशियलाइज़र बना सकते हैं और उससे डिफ़ॉल्ट पैरामीटर भेज सकते हैं। कृपया मुझे बताएं कि क्या आपको उत्तर मिलता है
user100

सुविधा "मुख्य" self.init के लिए अतिरिक्त है जबकि डिफ़ॉल्ट पैरामीटर के साथ self.init "मुख्य" self.init के लिए प्रतिस्थापन हैhackingwithswift.com/example-code/language/…
user1105951

@ shripad20 एक स्पष्टीकरण के लिए नीचे मेरे उदाहरण की जाँच करें जहां सुविधा आरोहणकर्ताओं ने डिफ़ॉल्ट मानों को हराया। आशा है कि इससे सहायता मिलेगी।
क्रिस ग्रेफ

14

यहाँ एक सरल उदाहरण है, Apple डेवलपर पोर्टल से लिया गया है ।

मूल रूप से नामित इनिशियलाइज़र है init(name: String), यह सुनिश्चित करता है कि सभी संग्रहित संपत्तियों को इनिशियलाइज़ किया जाए।

init()सुविधा प्रारंभकर्ता, कोई तर्क ले, स्वत: का मान सेट nameसंग्रहीत संपत्ति के लिए [Unnamed]नामित प्रारंभकर्ता का उपयोग करके।

class Food {
    let name: String

    // MARK: - designated initializer
    init(name: String) {
        self.name = name
    }

    // MARK: - convenience initializer
    convenience init() {
        self.init(name: "[Unnamed]")
    }
}

// MARK: - Examples
let food = Food(name: "Cheese") // name will be "Cheese"
let food = Food()               // name will be "[Unnamed]"

यह उपयोगी है, जब आप बड़ी कक्षाओं के साथ काम कर रहे हैं, कम से कम कुछ संग्रहीत गुणों के साथ। मैं Apple डेवलपर पोर्टल पर वैकल्पिक और वंशानुक्रम के बारे में कुछ और पढ़ने की सिफारिश करूंगा


6

जहाँ सुविधा इनिशियलाइज़र ने डिफ़ॉल्ट पैरामीटर मान सेट करना हराया

मेरे लिए, convenience initializersउपयोगी हैं यदि एक वर्ग संपत्ति के लिए बस एक डिफ़ॉल्ट मान सेट करने के लिए और अधिक है।

नामित इनिट के साथ वर्ग कार्यान्वयन ()

अन्यथा, मैं बस initपरिभाषा में डिफ़ॉल्ट मान सेट करूँगा , उदाहरण के लिए:

class Animal {

    var race: String // enum might be better but I am using string for simplicity
    var name: String
    var legCount: Int

    init(race: String = "Dog", name: String, legCount: Int = 4) {
        self.race = race
        self.name = name
        self.legCount = legCount // will be 4 by default
    }
}

सुविधा init के साथ वर्ग विस्तार ()

हालाँकि, डिफ़ॉल्ट मान सेट करने के अलावा और भी बहुत कुछ हो सकता है, और यह convenience initializersकाम में आता है:

extension Animal {
    convenience init(race: String, name: String) {
        var legs: Int

        if race == "Dog" {
            legs = 4
        } else if race == "Spider" {
            legs = 8
        } else {
            fatalError("Race \(race) needs to be implemented!!")
        }

        // will initialize legCount automatically with correct number of legs if race is implemented
        self.init(race: race, name: name, legCount: legs)
    }
}

उपयोग के उदाहरण

// default init with all default values used
let myFirstDog = Animal(name: "Bello")

// convenience init for Spider as race
let mySpider = Animal(race: "Spider", name: "Itzy")

// default init with all parameters set by user
let myOctopus = Animal(race: "Octopus", name: "Octocat", legCount: 16)

// convenience init with Fatal error: Race AlienSpecies needs to be implemented!!
let myFault = Animal(race: "AlienSpecies", name: "HelloEarth")

1
अच्छी तरह से और सरल यहाँ समझाया
vivi

4

एक सुविधा आरम्भिक को एक वर्ग विस्तार में परिभाषित किया जा सकता है । लेकिन एक मानक एक - नहीं कर सकता।


1
हालांकि इस सवाल का पूरा जवाब नहीं है, यह एक ऐसी चीज है जिसे मैंने अभी तक नहीं माना था, धन्यवाद!
मार्क-आंद्रे वीबेज़हैन

3

convenience initयह मूल्यों के साथ एक वर्ग प्रारंभ करने में वैकल्पिक बना देता है।

यहाँ छवि विवरण दर्ज करें

यहाँ छवि विवरण दर्ज करें


3

यह समझ में आता है कि यदि आपका उपयोग मामला एक इनीशियलाइज़र को उसी क्लास में एक इनिशियलाइज़र को कॉल करने के लिए है

खेल के मैदान में ऐसा करने की कोशिश करें

class Player {
    let name: String
    let level: Int

    init(name: String, level: Int) {
        self.name = name
        self.level = level
    }
    
    init(name: String) {
        self.init(name: name, level: 0) //<- Call the initializer above?

        //Sorry you can't do that. How about adding a convenience keyword?
    }
}

Player(name:"LoseALot")

सुविधा कीवर्ड के साथ

class Player {
    let name: String
    let level: Int

    init(name: String, level: Int) {
        self.name = name
        self.level = level
    }
    
    //Add the convenience keyword
    convenience init(name: String) {
        self.init(name: name, level: 0) //Yes! I am now allowed to call my fellow initializer!
    }
}

2

नोट: पूरा पाठ पढ़ें

नामित इनिशियलाइज़र एक क्लास के लिए प्राइमरी इनिशियलाइज़र हैं। एक नामित इनिशियलाइज़र उस वर्ग द्वारा शुरू की गई सभी संपत्तियों को पूरी तरह से इनिशियलाइज़ करता है और सुपरक्लास चेन तक की इनिशियलाइज़ेशन प्रक्रिया को जारी रखने के लिए एक उपयुक्त सुपरक्लास इनिशलाइज़र को कॉल करता है।

सुविधा इनिशियलाइज़र माध्यमिक हैं, एक वर्ग के लिए इनिशियलाइज़र का समर्थन करते हैं। आप एक ही वर्ग से नामित इनिशियलाइज़र को कॉल करने के लिए एक सुविधा इनिशियलाइज़र को परिभाषित कर सकते हैं क्योंकि सुविधा इनिशियलाइज़र कुछ निर्दिष्ट इनिशियलाइज़र के मापदंडों के साथ डिफ़ॉल्ट पर सेट है।

वर्गों के लिए नामित इनिशियलाइज़र उसी तरह लिखे जाते हैं जैसे कि वैल्यू टाइप्स के लिए सिंपल इनिशियलाइज़र:

init(parameters) {
statements
}

सुविधा इनिशियलाइज़र एक ही शैली में लिखे गए हैं, लेकिन init कीवर्ड से पहले रखी गई सुविधा संशोधक के साथ, एक स्थान द्वारा अलग किया गया है:

convenience init(parameters) {
statements
}

एक व्यावहारिक उदाहरण निम्नानुसार हैं:

class Food {
var name: String
init(name: String) {
    self.name = name
}
convenience init() {
    self.init(name: "[Unnamed]")
}
}
let namedMeat = Food(name: "Bacon")
// namedMeat's name is "Bacon”

Init (नाम: स्ट्रिंग) फूड क्लास से इनिशियलाइज़र को निर्दिष्ट इनिशियलाइज़र के रूप में प्रदान किया जाता है क्योंकि यह सुनिश्चित करता है कि नए फ़ूड इंस्टेंस के सभी संग्रहीत गुण पूरी तरह से इनिशियलाइज़ किए गए हों। खाद्य वर्ग के पास सुपरक्लास नहीं है, और इसलिए इनिट (नाम: स्ट्रिंग) इनिशियलाइज़र को इसके इनिशियलाइज़ेशन को पूरा करने के लिए सुपर.इनिट () को कॉल करने की आवश्यकता नहीं है।

“खाद्य वर्ग भी कोई तर्क के साथ, एक सुविधा इनिशियलाइज़र, इनिट () प्रदान करता है। Init () initializer एक नए भोजन के लिए एक डिफ़ॉल्ट प्लेसहोल्डर नाम प्रदान करता है जिसे फ़ूड क्लास के init (नाम: String) में एक नाम मान के साथ दर्शाया जाता है: "

let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]”

पदानुक्रम में दूसरा वर्ग भोजन का एक उपवर्ग है जिसे रेसिपीइन्ग्रिडिएंट कहा जाता है। पकाने की विधि में रेसिपीइन्ग्रेडिएंट क्लास मॉडल एक घटक है। यह मात्रा नामक एक Int गुण का परिचय देता है (नाम संपत्ति के अलावा यह भोजन से प्राप्त होता है) और RecipeIngredient इंस्टेंस बनाने के लिए दो इनिशियलाइज़र को परिभाषित करता है:

class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
    self.quantity = quantity
    super.init(name: name)
}
override convenience init(name: String) {
    self.init(name: name, quantity: 1)
}
}

RecipeIngredient वर्ग में एक एकल निर्दिष्ट इनिशियलाइज़र, init (नाम: स्ट्रिंग, मात्रा: Int) है, जिसका उपयोग नए RecipeIngredient उदाहरण के सभी गुणों को पॉप्युलेट करने के लिए किया जा सकता है। यह इनिशलाइज़र पास की मात्रा तर्क को गुण संपत्ति में निर्दिष्ट करके शुरू होता है, जो कि RecipeIngredient द्वारा पेश की गई एकमात्र नई संपत्ति है। ऐसा करने के बाद, इनिलाइज़र खाद्य वर्ग के इनिट (नाम: स्ट्रिंग) इनिशलाइज़र को दर्शाता है।

पृष्ठ: 536 अंश से: Apple Inc. "स्विफ्ट प्रोग्रामिंग लैंग्वेज (स्विफ्ट 4)।" iBooks। https://itunes.apple.com/pk/book/the-swift-programming-language-swift-4-0-3/id881256329?mt=11


2

यह तब काम आता है जब आपको किसी वर्ग के लिए प्रत्येक संपत्ति को निर्दिष्ट करने की आवश्यकता नहीं होती है। इसलिए, उदाहरण के लिए, यदि मैं 100 के एचपी मूल्य को शुरू करने के साथ सभी रोमांच बनाना चाहता हूं, तो मैं इस सुविधा सुविधा का उपयोग करूंगा और बस एक नाम जोड़ूंगा । यह कोड में बहुत कटौती करने जा रहा है।

class Adventure { 

// Instance Properties

    var name: String
    var hp: Int
    let maxHealth: Int = 100

    // Optionals

    var specialMove: String?

    init(name: String, hp: Int) {

        self.name = name
        self.hp = hp
    }

    convenience init(name: String){
        self.init(name: name, hp: 100)
    }
}

1

सभी उत्तर अच्छे लगते हैं लेकिन, इसे सरल उदाहरण से समझते हैं

class X{                                     
   var temp1
   init(a: Int){
        self.temp1 = a
       }

अब, हम जानते हैं कि एक वर्ग दूसरे वर्ग को विरासत में दे सकता है

class Z: X{                                     
   var temp2
   init(a: Int, b: Int){
        self.temp2 = b
        super.init(a: a)
       }

अब, इस स्थिति में कक्षा Z के लिए उदाहरण बनाते समय, आपको दोनों मान 'a' और 'b' प्रदान करने होंगे।

let z = Z(a: 1, b: 2)

लेकिन, क्या होगा यदि आप केवल बी के मूल्य को पास करना चाहते हैं और बाकी को दूसरों के लिए डिफ़ॉल्ट मान लेना चाहते हैं, तो उस स्थिति में आपको अन्य मानों को एक डिफ़ॉल्ट मान को शुरू करने की आवश्यकता है। लेकिन रुको, कैसे? यू के लिए इसे केवल कक्षा में पहले ही अच्छी तरह से सेट करने की आवश्यकता है।

//This is inside the class Z, so consider it inside class Z's declaration
convenience init(b: Int){
    self.init(a: 0, b: b)
}
convenience init(){
    self.init(a: 0, b: 0)
}

और अब, आप चर के लिए कुछ, सभी या कोई भी मान प्रदान करने के साथ वर्ग Z के उदाहरण बना सकते हैं।

let z1 = Z(b: 2)
let z2 = Z()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.