Ich habe Probleme, den Unterschied zwischen beiden oder den Zweck des Convenience Init zu verstehen. Vielen Dank
swift
initialization
convenience-methods
Chino Pan
quelle
quelle
Antworten:
Standard
init
:convenience init
::gemäß der Swift-Dokumentation
Kurz gesagt bedeutet dies, dass Sie einen praktischen Initialisierer verwenden können, um das Aufrufen eines bestimmten Initialisierers schneller und "bequemer" zu machen. Convenience-Initialisierer erfordern daher die Verwendung von
self.init
anstelle des, densuper.init
Sie möglicherweise bei einer Überschreibung eines bestimmten Initialisierers sehen.Pseudocode-Beispiel:
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) }
Ich benutze diese häufig beim Erstellen von benutzerdefinierten Ansichten und solchen, die lange Initialisierer mit hauptsächlich Standardeinstellungen haben. Die Dokumente erklären besser als ich, sehen Sie sie sich an!
quelle
Convenience-Initialisierer werden verwendet, wenn Sie eine Klasse mit vielen Eigenschaften haben, die es irgendwie "schmerzhaft" macht, den Witz immer mit all diesen Variablen zu initialisieren. Was Sie also mit dem Convenience-Initialisierer tun, ist, dass Sie nur einige der Variablen übergeben, um die zu initialisieren Objekt, und weisen Sie den Rest mit einem Standardwert zu. Es gibt ein sehr gutes Video auf der Ray Wenderlich-Website, nicht sicher, ob es kostenlos ist oder nicht, weil ich ein bezahltes Konto habe. Hier ist ein Beispiel, in dem Sie sehen können, dass ich mein Objekt nicht mit all diesen Variablen initialisiere, sondern nur einen Titel gebe.
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
quelle
Hier ist ein einfaches Beispiel aus dem Apple Developer Portal .
Grundsätzlich ist der festgelegte Initialisierer der
init(name: String)
, der sicherstellt, dass alle gespeicherten Eigenschaften initialisiert werden.Der
init()
Convenience-Initialisierer setzt ohne Argument automatisch den Wert dername
gespeicherten Eigenschaft[Unnamed]
mithilfe des angegebenen Initialisierers auf.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]"
Dies ist nützlich, wenn Sie mit großen Klassen mit mindestens einigen gespeicherten Eigenschaften arbeiten. Ich würde empfehlen, mehr über Optionen und Vererbung im Apple Developer Portal zu lesen .
quelle
Wo Convenience-Initialisierer die Einstellung der Standardparameterwerte übertreffen
Für mich
convenience initializers
sind sie nützlich, wenn mehr zu tun ist, als einfach einen Standardwert für eine Klasseneigenschaft festzulegen.Klassenimplementierung mit bezeichnetem init ()
Andernfalls würde ich einfach den Standardwert in der
init
Definition festlegen , z.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 } }
Klassenerweiterung mit Komfort init ()
Es kann jedoch mehr zu tun geben, als nur einen Standardwert festzulegen, und das ist
convenience initializers
nützlich: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) } }
Anwendungsbeispiele
// 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")
quelle
Ein Convenience-Initialisierer kann in einer Klassenerweiterung definiert werden . Aber ein Standard - kann nicht.
quelle
Hinweis: Lesen Sie den gesamten Text
Bestimmte Initialisierer sind die primären Initialisierer für eine Klasse. Ein designierter Initialisierer initialisiert alle von dieser Klasse eingeführten Eigenschaften vollständig und ruft einen geeigneten Superklassen-Initialisierer auf, um den Initialisierungsprozess bis zur Superklassenkette fortzusetzen.
Convenience-Initialisierer sind sekundär und unterstützen Initialisierer für eine Klasse. Sie können einen Convenience-Initialisierer definieren, um einen bestimmten Initialisierer aus derselben Klasse wie den Convenience-Initialisierer aufzurufen, wobei einige der Parameter des festgelegten Initialisierers auf Standard gesetzt sind.
Bestimmte Initialisierer für Klassen werden wie einfache Initialisierer für Werttypen geschrieben:
init(parameters) { statements }
Convenience-Initialisierer werden im gleichen Stil geschrieben, jedoch mit dem Convenience-Modifikator vor dem Schlüsselwort init, getrennt durch ein Leerzeichen:
convenience init(parameters) { statements }
Ein praktisches Beispiel ist wie folgt:
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”
Der Initialisierer init (name: String) aus der Food-Klasse wird als designierter Initialisierer bereitgestellt, da er sicherstellt, dass alle gespeicherten Eigenschaften einer neuen Food-Instanz vollständig initialisiert werden. Die Food-Klasse hat keine Superklasse, daher muss der Initialisierer init (name: String) nicht super.init () aufrufen, um die Initialisierung abzuschließen.
„Die Food-Klasse bietet auch den Convenience-Initialisierer init () ohne Argumente. Der Initialisierer init () stellt einen Standardplatzhalternamen für ein neues Lebensmittel bereit, indem er an den Init (Name: String) der Lebensmittelklasse mit dem Namenswert [Unbenannt] delegiert: ”
“let mysteryMeat = Food() // mysteryMeat's name is "[Unnamed]”
Die zweite Klasse in der Hierarchie ist eine Unterklasse von Lebensmitteln namens RecipeIngredient. Die RecipeIngredient-Klasse modelliert eine Zutat in einem Kochrezept. Es führt eine Int-Eigenschaft namens Quantity ein (zusätzlich zu der Name-Eigenschaft, die es von Food erbt) und definiert zwei Initialisierer zum Erstellen von RecipeIngredient-Instanzen:
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) } }
Die RecipeIngredient-Klasse verfügt über einen einzelnen festgelegten Initialisierer, init (Name: String, Menge: Int), mit dem alle Eigenschaften einer neuen RecipeIngredient-Instanz aufgefüllt werden können. Dieser Initialisierer weist zunächst der übergebenen Mengeneigenschaft das übergebene Mengenargument zu. Dies ist die einzige neue Eigenschaft, die von RecipeIngredient eingeführt wurde. Anschließend delegiert der Initialisierer an den Initialisierer init (Name: String) der Food-Klasse.
Seite: 536 Auszug aus: Apple Inc. „Die Swift-Programmiersprache (Swift 4).“ iBooks. https://itunes.apple.com/pk/book/the-swift-programming-language-swift-4-0-3/id881256329?mt=11
quelle
Dies ist praktisch, wenn Sie nicht jede Eigenschaft für eine Klasse angeben müssen. Wenn ich zum Beispiel alle Abenteuer mit einem HP-Startwert von 100 erstellen möchte, würde ich diesen folgenden Convenience-Init verwenden und einfach einen Namen hinzufügen. Dies wird den Code erheblich reduzieren.
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) } }
quelle
Das
convenience init
macht es optional, eine Klasse mit Werten zu initialisieren.quelle
Alle Antworten klingen gut, aber lassen Sie es uns anhand eines einfachen Beispiels verstehen
class X{ var temp1 init(a: Int){ self.temp1 = a }
Jetzt wissen wir, dass eine Klasse eine andere Klasse erben kann
class Z: X{ var temp2 init(a: Int, b: Int){ self.temp2 = b super.init(a: a) }
In diesem Fall müssen Sie beim Erstellen einer Instanz für die Klasse Z beide Werte 'a' und 'b' angeben.
let z = Z(a: 1, b: 2)
Was ist jedoch, wenn Sie nur den Wert von b übergeben möchten und Rest den Standardwert für andere übernehmen soll? In diesem Fall müssen Sie andere Werte als Standardwert initialisieren. Aber warte wie?, Dafür musst du es vorher nur in der Klasse gut einstellen.
//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) }
Und jetzt können Sie Instanzen der Klasse Z erstellen, indem Sie einige, alle oder keine Werte für die Variablen angeben.
let z1 = Z(b: 2) let z2 = Z()
quelle
Es ist sinnvoll, wenn Ihr Anwendungsfall darin besteht, einen Initialisierer in einem anderen Initialisierer derselben Klasse aufzurufen .
Versuchen Sie dies auf dem Spielplatz zu tun
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")
Mit Convenience-Keyword
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! } }
quelle