As respostas existentes contam apenas metade da conveniencehistória. A outra metade da história, a metade que nenhuma das respostas existentes cobre, responde à pergunta que Desmond postou nos comentários:
Por que Swift me forçou a colocar conveniencena frente do meu inicializador só porque eu preciso ligar self.initdele? `
Eu o toquei levemente nesta resposta , na qual abordo várias regras de inicializador de Swift em detalhes, mas o foco principal estava na requiredpalavra. Mas essa resposta ainda estava abordando algo que é relevante para esta pergunta e esta resposta. Temos que entender como a herança do inicializador Swift funciona.
Como o Swift não permite variáveis não inicializadas, não é garantido que você herda todos (ou quaisquer) inicializadores da classe que você herda. Se subclassificarmos e adicionarmos variáveis de instância não inicializadas a nossa subclasse, paramos de herdar inicializadores. E até adicionarmos os inicializadores, o compilador gritará conosco.
Para ser claro, uma variável de instância não inicializada é qualquer variável de instância que não recebe um valor padrão (tendo em mente que os opcionais e opcionais implicitamente desembrulhados assumem automaticamente um valor padrão de nil).
Então, neste caso:
class Foo {
var a: Int
}
aé uma variável de instância não inicializada. Isso não será compilado a menos que forneça aum valor padrão:
class Foo {
var a: Int = 0
}
ou inicialize aem um método inicializador:
class Foo {
var a: Int
init(a: Int) {
self.a = a
}
}
Agora, vamos ver o que acontece se subclassificarmos Foo, não é?
class Bar: Foo {
var b: Int
init(a: Int, b: Int) {
self.b = b
super.init(a: a)
}
}
Certo? Adicionamos uma variável e um inicializador para definir um valor para bque ele seja compilado. Dependendo do idioma de origem, você pode esperar que Barherdou Fooo inicializador init(a: Int),. Mas isso não acontece. E como pôde? Como é Foodo init(a: Int)conhecimento como atribuir um valor para a bvariável que Baradicionou? Não faz. Portanto, não podemos inicializar uma Barinstância com um inicializador que não possa inicializar todos os nossos valores.
O que isso tem a ver convenience?
Bem, vejamos as regras sobre herança de inicializador :
Regra 1
Se sua subclasse não definir nenhum inicializador designado, ela herdará automaticamente todos os inicializadores designados da superclasse.
Regra 2
Se sua subclasse fornecer uma implementação de todos os inicializadores designados para sua superclasse - herdando-os de acordo com a regra 1 ou fornecendo uma implementação customizada como parte de sua definição -, ela herdará automaticamente todos os inicializadores de conveniência da superclasse.
Observe a Regra 2, que menciona os inicializadores de conveniência.
Portanto, o que a conveniencepalavra - chave faz é indicar quais inicializadores podem ser herdados por subclasses que adicionam variáveis de instância sem valores padrão.
Vamos dar uma Baseaula de exemplo :
class Base {
let a: Int
let b: Int
init(a: Int, b: Int) {
self.a = a
self.b = b
}
convenience init() {
self.init(a: 0, b: 0)
}
convenience init(a: Int) {
self.init(a: a, b: 0)
}
convenience init(b: Int) {
self.init(a: 0, b: b)
}
}
Observe que temos três convenienceinicializadores aqui. Isso significa que temos três inicializadores que podem ser herdados. E temos um inicializador designado (um inicializador designado é simplesmente qualquer inicializador que não seja um inicializador de conveniência).
Podemos instanciar instâncias da classe base de quatro maneiras diferentes:

Então, vamos criar uma subclasse.
class NonInheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
}
Nós estamos herdando de Base. Adicionamos nossa própria variável de instância e não atribuímos um valor padrão, portanto, devemos adicionar nossos próprios inicializadores. Nós adicionamos um, init(a: Int, b: Int, c: Int)mas isso não corresponde à assinatura do Baseclasse está designado initializer: init(a: Int, b: Int). Isso significa que não herdamos nenhum inicializador de Base:

Então, o que aconteceria se herdássemos Base, mas seguimos em frente e implementamos um inicializador que correspondesse ao inicializador designado Base?
class Inheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
convenience override init(a: Int, b: Int) {
self.init(a: a, b: b, c: 0)
}
}
Agora, além dos dois inicializadores que implementamos diretamente nesta classe, porque implementamos um inicializador que corresponde Baseao inicializador designado da classe, herdamos todos Baseos convenienceinicializadores da classe :

O fato de o inicializador com a assinatura correspondente ser marcado como conveniencenão faz diferença aqui. Isso significa apenas que Inheritorpossui apenas um inicializador designado. Portanto, se herdarmos de Inheritor, teríamos que implementar esse inicializador designado e herdaríamos Inheritoro inicializador de conveniência, o que, por sua vez, significa que implementamos todos Baseos inicializadores designados e podemos herdar seus convenienceinicializadores.