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.
class Person1 {
var name: String
var age: Int
var nationality: String
init(
name: String,
age: Int,
nationality: String = "Canadian"
) {
self.name = name
self.age = age
self.nationality = nationality
}
}
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:
class Person0 {
var name: String
var age: Int
required init(
name: String,
age: Int
) {
self.name = name
self.age = age
}
}
You can't just do this; Swift doesn't consider this to satisfy the requirement:
class Person1: Person0 {
var nationality: String
required init(
name: String,
age: Int,
nationality: String = "Canadian"
) {
self.nationality = nationality
super.init(
name: name,
age: age
)
}
}
Instead, you can either duplicate, like this:
required init(
name: String,
age: Int
) {
nationality = "Canadian"
super.init(
name: name,
age: age
)
}
init(
name: String,
age: Int,
nationality: String
) {
self.nationality = nationality
super.init(
name: name,
age: age
)
}
…or use one designated initializer, which actually does the work, and forward the required init along to it:
required convenience init(
name: String,
age: Int
) {
self.init(
name: name,
age: age,
nationality: "Canadian"
)
}
init(
name: String,
age: Int,
nationality: String
) {
self.nationality = nationality
super.init(
name: name,
age: age
)
}
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.
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.
If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers. – https://docs.swift.org/swift-book/LanguageGuide/Initialization.html
So, for example, when you use a convenience + designated combo, you get to skip rewriting a required init.
e.g.
Person2(name: "Terrance Phillip", age: 42)
compiles, from this:
class Person2: Person1 {
var flag: String
override convenience init(
name: String,
age: Int,
nationality: String
) {
self.init(
name: name,
age: age,
nationality: nationality,
flag: ""
)
}
init(
name: String,
age: Int,
nationality: String,
flag: String
) {
self.flag = flag
super.init(
name: name,
age: age,
nationality: nationality
)
}
}
That's also the same person as this:
Person3()
…given this:
class Person3: Person2 {
convenience init() {
self.init(
name: "Terrance Phillip",
age: 42
)
}
}
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.