I have read responses to similar questions here, but I am still puzzled regarding what would be the best implementation here, why, and is there any difference.
In this implementation, I have two initializers for the class
class Person1 {
var name: String
var age: Int
var nationality: String
init(name: String, age: Int, nationality: String) {
self.name = name
self.age = age
self.nationality = nationality
}
init(name:String, age: Int) {
self.name = name
self.age = age
self.nationality = "Canadian"
}
}
When I create an instance, I have the option of choosing from one or the other. If I choose the second one, I get the default nationality set as Canadian
let p1 = Person1(name: "Stewart", age: 40)
If I swap out that second initializer with the following convenience initializer,
convenience init(name: String, age: Int) {
self.init(name: name, age: age, nationality: "Canadian")
}
I can create the same instance the same way and get the same result. So what is the difference? I am finding difficulty finding a good example where a convenience initializer is the only way to accomplish creating a particular instance of a class that can't be accomplished by a second initializer like I did in the first example.
As it is, having your two initializers is Bad Code™. The way to express that exact example making use of the most appropriate Swift language feature, is, as Leo Dabus said, to use a default parameter value.
A convenience initializer is what you use when another initializer exists, and will save you code duplication.
For example, Let's say that you add a superclass, with a required init:
You can't just do this; Swift doesn't consider this to satisfy the requirement:
Instead, you can either duplicate, like this:
…or use one designated initializer, which actually does the work, and forward the required init along to it:
You can always duplicate code. A convenience initializer will never be the only way. In the simplest cases, like I'm showing here, you'll only have a partial line of duplication, per initializer. That's not a big deal. But deduplicating piles up, with inheritance.
So, for example, when you use a convenience + designated combo, you get to skip rewriting a required init.
e.g.
compiles, from this:
That's also the same person as this:
…given this:
As a guideline, use 1. default parameters and 2. convenience initializers whenever possible. (And as an extension of 2, transform designated initializers into convenience ones, in subclasses.) You will have to maintain less code.