Al crear subclases de UIButton en Swift, es fundamental comprender cómo funcionan los inicializadores y sus reglas de herencia. Este artículo explora estos conceptos a través de ejemplos prácticos.
Reglas de herencia de inicializadores
Swift define dos reglas fundamentales que gobiernan cómo las subclases heredan los inicializadores de sus clases padre:
Regla 1: Si una subclase no define ningún inicializador designado, hereda automáticamente todos los inicializadores designados de su superclase.
Regla 2: Si una subclase proporciona implementaciones para todos los inicializadores designados de su superclase, ya sea heredándolos según la Regla 1 o mediante implementaciones personalizadas, entonces hereda automáticamente todos los inicializadores de conveniencia de la superclase.
Override de inicializadores designados
Un aspecto importante es que las subclases pueden definir inicializadores de conveniencia que coincidan con los parámetros de un inicializador designado de la superclase. En estos casos, el inicializador de conveniencia debe marcarse con el modificador override, ya que está reemplazando la implementación del padre. Esto cumple con el requisito de proporcionar una implementación del inicializador designado heerdado.
Ejemplo práctico con UIButton
Vamos a crear una subclase de UIButton y explorar diferentes escenarios de inicialización.
Escenario 1: Subclase vacía
class BotonPersonalizado: UIButton {
}
Este código compila sin problemas porque la clase no define ningún inicializador propio, por lo que hereda automáticamente todos los inicializadores designados y de conveniencia de UIButton.
Escenario 2: Agregando un inicializador personalizado
class BotonPersonalizado: UIButton {
initPersonalizado() {
super.init()
}
}
Al agregar este inicializador, aparece una advertencia indicando que se requiere implementar init(coder:). Esto ocurre porque el inicializador que definimos se convierte en el inicializaodr designado de nuestra subclase, perdiendo así la herencia automática de inicializadores del padre. El protocolo NSCoding exige la implementación de este inicializador específico.
Escenario 3: Implementación requerida con NSCoder
class BotonPersonalizado: UIButton {
initPersonalizado() {
super.init()
}
required init(coder: NSCoder) {
fatalError("El inicializador NSCoder no está implementado")
}
}
Este código genera un error en tiempo de compilación. El problema radica en que el inicializador designado de la subclase debe llamar a un inicializador designado de la superclase, no a uno de conveinencia. UIButton no define inicializadores personalizados propios, por lo que su cadena de herencia es: UIButton → UIControl → UIView.
Escenario 4: Comprendiendo la jerarquía de herencia
La clase UIView tiene un único inicializador designado: init(frame:). Este es el método que debemos invocar desde nuestra subclase para satisfacer correctamente los requisitos de inicialización.
class BotonPersonalizado: UIButton {
initPersonalizado() {
super.init(frame: .zero)
}
required init(coder: NSCoder) {
super.init(coder: coder)
}
}
Este código compila correctamente porque ambos inicializadores designados de la subclase llaman apropiadamente a los inicializadores designados de la superclase, respetando la cadena de herencia establecida en el sistema.