Hay dos piezas absolutamente cruciales de información específica de Swift que faltan en las respuestas existentes que creo que ayudan a aclarar esto por completo.
- Si un protocolo especifica un inicializador como método requerido, ese inicializador debe marcarse con la
requiredpalabra clave de Swift .
- Swift tiene un conjunto especial de reglas de herencia con respecto a los
initmétodos.
El tl; dr es este:
Si implementa algún inicializador, ya no heredará ninguno de los inicializadores designados de la superclase.
Los únicos inicializadores, si los hay, que heredará, son los inicializadores de conveniencia de súper clase que apuntan a un inicializador designado que usted anuló.
Entonces ... ¿listo para la versión larga?
Swift tiene un conjunto especial de reglas de herencia con respecto a los initmétodos.
Sé que este fue el segundo de los dos puntos que hice, pero no podemos entender el primer punto, o por qué la requiredpalabra clave existe hasta que comprendamos este punto. Una vez que entendemos este punto, el otro se vuelve bastante obvio.
Toda la información que cubro en esta sección de esta respuesta proviene de la documentación de Apple que se encuentra aquí .
De los documentos de Apple:
A diferencia de las subclases en Objective-C, las subclases Swift no heredan sus inicializadores de superclase de forma predeterminada. El enfoque de Swift evita una situación en la que un inicializador simple de una superclase es heredado por una subclase más especializada y se utiliza para crear una nueva instancia de la subclase que no se inicializa de forma completa o correcta.
El énfasis es mío.
Entonces, directamente desde los documentos de Apple, vemos que las subclases Swift no siempre heredarán (y generalmente no) los initmétodos de sus superclases .
Entonces, ¿cuándo heredan de su superclase?
Hay dos reglas que definen cuándo una subclase hereda los initmétodos de su padre. De los documentos de Apple:
Regla 1
Si su subclase no define ningún inicializador designado, hereda automáticamente todos sus inicializadores designados de superclase.
Regla 2
Si su subclase proporciona una implementación de todos sus inicializadores designados de superclase, ya sea al heredarlos según la regla 1 o al proporcionar una implementación personalizada como parte de su definición, entonces hereda automáticamente todos los inicializadores de conveniencia de superclase.
Regla 2 no es particularmente relevante a esta conversación porque SKSpriteNode's init(coder: NSCoder)es poco probable que sea un método de conveniencia.
Entonces, su InfoBarclase estaba heredando el requiredinicializador hasta el punto que agregó init(team: Team, size: CGSize).
Si no hubiera proporcionado este initmétodo y, en su lugar, hubiera hecho que InfoBarlas propiedades agregadas de usted fueran opcionales o si les hubiera proporcionado valores predeterminados, entonces todavía habría estado heredando SKSpriteNodelas suyas init(coder: NSCoder). Sin embargo, cuando agregamos nuestro propio inicializador personalizado, dejamos de heredar los inicializadores designados de nuestra superclase (e inicializadores convenientes que no apuntaban a los inicializadores que implementamos).
Entonces, como un ejemplo simplista, presento esto:
class Foo {
var foo: String
init(foo: String) {
self.foo = foo
}
}
class Bar: Foo {
var bar: String
init(foo: String, bar: String) {
self.bar = bar
super.init(foo: foo)
}
}
let x = Bar(foo: "Foo")
Que presenta el siguiente error:
Falta el argumento para el parámetro 'bar' en la llamada.

Si esto fuera Objective-C, no tendría problemas para heredar. Si inicializamos a Barcon initWithFoo:en Objective-C, la self.barpropiedad simplemente sería nil. Es probablemente no es muy bueno, pero es perfectamente válida del estado para el objeto a ser. Es no un estado perfectamente válido para el objeto Swift para estar en. self.barNo es un opcional y no puede ser nil.
Una vez más, la única forma en que heredamos los inicializadores es no proporcionar el nuestro. Entonces, si tratamos de heredar eliminando Bar's init(foo: String, bar: String), como tal:
class Bar: Foo {
var bar: String
}
Ahora volvemos a heredar (más o menos), pero esto no se compilará ... y el mensaje de error explica exactamente por qué no heredamos los initmétodos de superclase :
Problema: la clase 'Bar' no tiene inicializadores
Fix-It: la propiedad 'barra' almacenada sin inicializadores evita los inicializadores sintetizados
Si hemos agregado propiedades almacenadas en nuestra subclase, no hay una manera rápida de crear una instancia válida de nuestra subclase con los inicializadores de la superclase que posiblemente no podrían conocer las propiedades almacenadas de nuestra subclase.
Bien, bien, ¿por qué tengo que implementarlo init(coder: NSCoder)? ¿Por qué es required?
Los initmétodos de Swift pueden jugar con un conjunto especial de reglas de herencia, pero la conformidad del protocolo todavía se hereda en la cadena. Si una clase primaria se ajusta a un protocolo, sus subclases deben cumplir con ese protocolo.
Por lo general, esto no es un problema, porque la mayoría de los protocolos solo requieren métodos que no cumplen con las reglas de herencia especiales en Swift, por lo que si está heredando de una clase que se ajusta a un protocolo, también está heredando todos los métodos o propiedades que permiten que la clase satisfaga la conformidad del protocolo.
Sin embargo, recuerde, los initmétodos de Swift se rigen por un conjunto especial de reglas y no siempre se heredan. Debido a esto, una clase que se ajusta a un protocolo que requiere initmétodos especiales (como NSCoding) requiere que la clase marque esos initmétodos como required.
Considere este ejemplo:
protocol InitProtocol {
init(foo: Int)
}
class ConformingClass: InitProtocol {
var foo: Int
init(foo: Int) {
self.foo = foo
}
}
Esto no se compila. Genera la siguiente advertencia:
Problema: el requisito de inicializador 'init (foo :)' solo puede cumplirse con un inicializador 'requerido' en la clase no final 'ConformingClass'
Fix-It: se requiere insertar
Quiere que haga el init(foo: Int)inicializador requerido. También podría hacerlo feliz haciendo la clase final(lo que significa que no se puede heredar la clase).
Entonces, ¿qué pasa si subclase? Desde este punto, si subclase, estoy bien. Sin embargo, si agrego algunos inicializadores, de repente ya no estoy heredando init(foo:). Esto es problemático porque ahora ya no me estoy conformando con el InitProtocol. No puedo subclase de una clase que se ajusta a un protocolo y luego, de repente, decido que ya no quiero cumplir con ese protocolo. He heredado la conformidad del protocolo, pero debido a la forma en que Swift trabaja con la initherencia del método, no heredé parte de lo que se requiere para cumplir con ese protocolo y debo implementarlo.
Bien, todo esto tiene sentido. Pero, ¿por qué no puedo obtener un mensaje de error más útil?
Podría decirse que el mensaje de error podría ser más claro o mejor si especifica que su clase ya no se ajusta al NSCodingprotocolo heredado y que para solucionarlo debe implementarlo init(coder: NSCoder). Por supuesto.
Pero Xcode simplemente no puede generar ese mensaje porque ese no siempre será el problema real de no implementar o heredar un método requerido. Hay al menos otra razón para hacer initmétodos requiredademás de la conformidad del protocolo, y son los métodos de fábrica.
Si quiero escribir un método de fábrica adecuado, necesito especificar el tipo de retorno que será Self(el equivalente de Swift de Objective-C instanceType). Pero para hacer esto, en realidad necesito usar un requiredmétodo inicializador.
class Box {
var size: CGSize
init(size: CGSize) {
self.size = size
}
class func factory() -> Self {
return self.init(size: CGSizeZero)
}
}
Esto genera el error:
La construcción de un objeto de tipo de clase 'Self' con un valor de metatipo debe usar un inicializador 'obligatorio'

Es básicamente el mismo problema. Si subclasificamos Box, nuestras subclases heredarán el método de la clase factory. Entonces podríamos llamar SubclassedBox.factory(). Sin embargo, sin la requiredpalabra clave en el init(size:)método, Boxno se garantiza que las subclases hereden la self.init(size:)que factoryestá llamando.
Por lo tanto, debemos hacer ese método requiredsi queremos un método de fábrica como este, y eso significa que si nuestra clase implementa un método como este, tendremos un requiredmétodo de inicialización y nos encontraremos exactamente con los mismos problemas que ha encontrado aquí con el NSCodingprotocolo
En última instancia, todo se reduce a la comprensión básica de que los inicializadores de Swift juegan con un conjunto ligeramente diferente de reglas de herencia, lo que significa que no está garantizado que herede los inicializadores de su superclase. Esto sucede porque los inicializadores de superclase no pueden conocer sus nuevas propiedades almacenadas y no pueden instanciar su objeto en un estado válido. Pero, por varias razones, una superclase puede marcar un inicializador como required. Cuando lo hace, podemos emplear uno de los escenarios muy específicos por los cuales realmente heredamos el requiredmétodo, o debemos implementarlo nosotros mismos.
Sin embargo, el punto principal aquí es que si recibimos el error que ves aquí, significa que tu clase no está implementando el método en absoluto.
Como quizás un último ejemplo para profundizar en el hecho de que las subclases de Swift no siempre heredan los initmétodos de sus padres (lo cual creo que es absolutamente central para comprender completamente este problema), considere este ejemplo:
class Foo {
init(a: Int, b: Int, c: Int) {
// do nothing
}
}
class Bar: Foo {
init(string: String) {
super.init(a: 0, b: 1, c: 2)
// do more nothing
}
}
let f = Foo(a: 0, b: 1, c: 2)
let b = Bar(a: 0, b: 1, c: 2)
Esto no se puede compilar.

El mensaje de error que da es un poco engañoso:
Argumento adicional 'b' en llamada
Pero el punto es Barque no hereda ninguno de Foolos initmétodos porque no ha satisfecho ninguno de los dos casos especiales para heredar initmétodos de su clase padre.
Si esto fuera Objective-C, heredaríamos eso initsin problema, porque Objective-C está perfectamente feliz de no inicializar las propiedades de los objetos (aunque como desarrollador, no debería haber estado contento con esto). En Swift, esto simplemente no servirá. No puede tener un estado no válido, y heredar inicializadores de superclase solo puede conducir a estados de objeto no válidos.
init(collection:MPMediaItemCollection). Debe proporcionar una colección real de elementos de medios; ese es el punto de esta clase. Esta clase simplemente no puede ser instanciada sin una. Analizará la colección e inicializará una docena de variables de instancia. ¡Ese es el objetivo de que este sea el único inicializador designado! Por lo tanto,init(coder:)no tiene MPMediaItemCollection significativo (o incluso sin sentido) para suministrar aquí; solo elfatalErrorenfoque es correcto.