web-dev-qa-db-fra.com

Quelle est la différence entre la commodité init vs init dans Swift, des exemples explicites mieux

J'ai du mal à comprendre la différence entre les deux, ou le but de la commod init. Merci

53
Chino Pan

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!

75
treyhakanson

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
49

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 .

11
dirtydanee

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

2
Abuzar Manzoor

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)
    }
}
2
Nirav

Là où les initialiseurs de commodité battent les valeurs par défaut des paramètres

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.

Implémentation de classe avec init () désigné

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
    }
}

Extension de classe avec commodité init ()

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)
    }
}

Exemples d'utilisation

// 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")
0
Chris Graf