Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between convenience init vs init in swift, explicit examples better

I am having troubles to understand the difference between both, or the purpose of the convenience init.

like image 248
Chino Pan Avatar asked Oct 17 '16 18:10

Chino Pan


People also ask

What is the difference between convenience and designated initializer?

A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up to the superclass chain. Convenience initializers are secondary, supporting initializers for a class.

Why do we need convenience initializer of the same task can be obtained with designated initializer?

A convenience initializer is a secondary initializer that must call a designated initializer of the same class. It is useful when you want to provide default values or other custom setup. A class does not require convenience initializers.

Can we override convenience init Swift?

Conversely, if you write a subclass initializer that matches a superclass convenience initializer, that superclass convenience initializer can never be called directly by your subclass, as per the rules described above in Initializer Delegation for Class Types.


4 Answers

Standard init:

Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.

convenience init:

Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.

per the Swift Documentation

In a nutshell, this means that you can use a convenience initializer to make calling a designated initializer faster and more "convenient". So convenience initializers require the use of self.init instead of the super.init you might see in an override of a designated initializer.

pseudocode example:

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

I use these a lot when creating custom views and such that have long initializers with mainly defaults. The docs do a better job explaining than I can, check them out!

like image 62
treyhakanson Avatar answered Oct 20 '22 12:10

treyhakanson


Convenience initializers are used when you have some class with a lot of properties that makes it kind of "Painful" to always initialize wit with all that variables, so what you do with convenience initializer is that you just pass some of the variables to initialize the object, and assign the rest with a default value. There is a very good video on Ray Wenderlich website, not sure its free or not because I have a paid account. Here is an example where you can see that instead of initializing my object with all those variables Im just giving it a title.

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
like image 35
Mago Nicolas Palacios Avatar answered Oct 20 '22 11:10

Mago Nicolas Palacios


Here is a simply example, taken from the Apple Developer portal.

Basicly the designated initializer is the init(name: String), it ensure that all stored properties are initialized.

The init() convenience initializer, taking no argument, automaticly sets the value of name stored property to [Unnamed] by using the designated initializer.

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]"

It is usefull, when you are dealing with large classes, with at least a few stored properties. I would recommend to read some more about optionals and inheritance at the Apple Developer portal.

like image 27
dirtydanee Avatar answered Oct 20 '22 13:10

dirtydanee


Where convenience initializers beat setting default parameter values

For me, convenience initializers are useful if there is more to do than simply set a default value for a class property.

Class implementation with designated init()

Otherwise, I would simply set the default value in the init definition, e.g.:

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

Class extension with convenience init()

However, there might be more to do than simply set a default value, and that is where convenience initializers come in handy:

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

Usage examples

// 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")
like image 38
Chris Graf Avatar answered Oct 20 '22 12:10

Chris Graf