J'ai du mal à comprendre la différence entre les deux, ou le but de la commod init. Merci
Standard init
:
Les initialiseurs désignés sont les initialiseurs principaux d'une classe. Un initialiseur désigné initialise complètement toutes les propriétés introduites par cette classe et appelle un initialiseur de superclasse approprié pour poursuivre le processus d'initialisation dans la chaîne de superclasse.
convenience init
:
Les initialiseurs de commodité sont secondaires et prennent en charge les initialiseurs d’une classe. Vous pouvez définir un initialiseur de commodité pour appeler un initialiseur désigné de la même classe que l’initialiseur de commodité avec certains paramètres de l’initialiseur désigné définis sur des valeurs par défaut. Vous pouvez également définir un initialiseur de confort pour créer une instance de cette classe pour un type de cas d'utilisation ou de valeur d'entrée spécifique.
selon le Swift Documentation
en gros, tout ce que cela signifie signifie que vous utilisez un initialiseur pratique pour rendre l’appel d’un initialiseur désigné plus rapide et plus "pratique". Donc, les initialiseurs pratiques nécessitent l’utilisation de self.init
au lieu de quelque chose comme le super.init
que vous verriez dans un remplacement d'un initialiseur désigné.
exemple de pseudocode:
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)
}
J'utilise beaucoup ceux-ci lors de la création de vues personnalisées, notamment avec des initialiseurs longs qui ont principalement des valeurs par défaut. Les docs font un meilleur travail que moi pour expliquer, vérifiez-les!
Les initialiseurs de commodité sont utilisés lorsque vous avez une classe avec beaucoup de propriétés qui le rend assez "douloureux" pour toujours initialiser avec toutes ces variables objet, et attribuez au reste une valeur par défaut. Il y a une très bonne vidéo sur le site Web de Ray Wenderlich, ni sûre ni gratuite car je possède un compte payant. Voici un exemple où vous pouvez voir cela au lieu d’initialiser mon objet avec toutes ces variables, je lui donne simplement un titre.
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
Voici un exemple simple, tiré du portail pour développeurs Apple .
En gros, l’initialiseur désigné est la init(name: String)
, il s’assure que toutes les propriétés stockées sont initialisées.
L'initialisateur de commodité init()
, ne prenant aucun argument, définit automatiquement la valeur de la propriété stockée name
sur [Unnamed]
en utilisant l’initialiseur désigné.
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]"
C'est utile, quand vous avez affaire à de grandes classes, avec au moins quelques propriétés stockées. Je vous recommande d’en lire un peu plus sur les options et l’héritage sur le portail de développeur Apple .
Note: Lire le texte entier
Les initialiseurs désignés sont les initialiseurs principaux d'une classe. Un initialiseur désigné initialise complètement toutes les propriétés introduites par cette classe et appelle un initialiseur de superclasse approprié pour poursuivre le processus d'initialisation jusqu'à la chaîne de superclasse.
Les initialiseurs de commodité sont secondaires et prennent en charge les initialiseurs d’une classe. Vous pouvez définir un initialiseur de confort pour appeler un initialiseur désigné de la même classe que l’initialiseur de confort, certains paramètres de l’initialiseur désigné étant définis par défaut.
Les initialiseurs désignés pour les classes s’écrivent de la même manière que les simples initialiseurs pour les types de valeur:
init(parameters) {
statements
}
Les initialiseurs de commodité sont écrits dans le même style, mais avec le modificateur de commodité placé devant le mot clé init, séparés par un espace:
convenience init(parameters) {
statements
}
Un exemple pratique sont les suivants:
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”
L'initialiseur init (name: String) de la classe Food est fourni en tant qu'initialiseur désigné car il garantit que toutes les propriétés stockées d'une nouvelle instance Food sont complètement initialisées. La classe Food n'a pas de superclasse et l'initialiseur init (name: String) n'a donc pas besoin d'appeler super.init () pour terminer son initialisation.
"La classe Food fournit également un initialiseur de commodité, init (), sans argument. L’initialiseur init () fournit un nom d’espace réservé par défaut pour un nouvel aliment en le délégant à init (name: String) de la classe Food avec la valeur de nom [Unnamed]: ”
“let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]”
La deuxième classe de la hiérarchie est une sous-classe de Food appelée RecipeIngredient. La classe RecipeIngredient modélise un ingrédient dans une recette de cuisine. Il introduit une propriété Int appelée quantité (en plus de la propriété name héritée de Food) et définit deux initialiseurs pour la création d'instances 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)
}
}
La classe RecipeIngredient a un seul initialiseur désigné, init (name: String, quantité: Int), qui peut être utilisé pour renseigner toutes les propriétés d'une nouvelle instance RecipeIngredient. Cet initialiseur commence par affecter l'argument de quantité passé à la propriété de quantité, qui est la seule nouvelle propriété introduite par RecipeIngredient. Après cela, l’initialiseur délègue jusqu’à l’initialiseur init (name: String) de la classe Food.
page: 536 Extrait de: Apple Inc. “Le Swift) (Swift 4).” iBooks. https: // iTunes. Apple.com/pk/book/the-Swift-programming-language-Swift-4-0-3/id881256329?mt=11
Il est donc pratique lorsque vous n'avez pas besoin de spécifier chaque propriété d'une classe. Ainsi, par exemple, si je veux créer toutes les aventures avec une valeur de départ de 100 pour HP, j’utiliserais ce qui suit commod init et ajouterais simplement un nom. Cela va beaucoup réduire le code.
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)
}
}
Pour moi, convenience initializers
sont utiles s’il ne suffit pas de définir une valeur par défaut pour une propriété de classe.
Sinon, je définirais simplement la valeur par défaut dans la définition de init
, par exemple:
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
}
}
Cependant, il pourrait y avoir plus à faire que simplement définir une valeur par défaut, et c’est là que convenience initializers
être utile:
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")