¿Cómo puedo hacer una referencia de protocolo débil en Swift 'puro' (sin @objc)?
weak
Las referencias no parecen funcionar en Swift a menos que se protocol
declare a como @objc
, lo cual no quiero en una aplicación Swift pura.
Este código genera un error de compilación ( weak
no se puede aplicar a tipos que no sean de clase MyClassDelegate
):
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate {
}
Necesito anteponer el protocolo con @objc
, entonces funciona.
Pregunta: ¿Cuál es la forma Swift "pura" de lograr un weak
delegate
?
Debe declarar el tipo de protocolo como AnyObject
.
protocol ProtocolNameDelegate: AnyObject {
// Protocol stuff goes here
}
class SomeClass {
weak var delegate: ProtocolNameDelegate?
}
Al usarlo AnyObject
, dice que solo las clases pueden ajustarse a este protocolo, mientras que las estructuras o enumeraciones no pueden.
Respuesta complementaria
Siempre estuve confundido acerca de si los delegados deberían ser débiles o no. Recientemente aprendí más sobre los delegados y cuándo usar referencias débiles, así que permítanme agregar algunos puntos adicionales aquí por el bien de los futuros espectadores.
El propósito de utilizar la
weak
palabra clave es evitar ciclos de referencia fuertes (ciclos de retención). Los ciclos de referencia fuertes ocurren cuando dos instancias de clase tienen fuertes referencias entre sí. Sus recuentos de referencias nunca llegan a cero, por lo que nunca se les desasigna.Solo necesitas usarlo
weak
si el delegado es una clase. Las estructuras y enumeraciones rápidas son tipos de valores (sus valores se copian cuando se crea una nueva instancia), no tipos de referencia, por lo que no crean ciclos de referencia fuertes .weak
las referencias son siempre opcionales (de lo contrario, usaríaunowned
) y siempre usanvar
(notlet
) para que lo opcional se pueda configurarnil
cuando se cancele la asignación.Naturalmente, una clase principal debería tener una fuerte referencia a sus clases secundarias y, por lo tanto, no utilizar la
weak
palabra clave. Sin embargo, cuando un niño quiere una referencia a su padre, debe convertirla en una referencia débil utilizando laweak
palabra clave.weak
debe usarse cuando desee una referencia a una clase que no es de su propiedad, no solo para un niño que hace referencia a su padre. Cuando dos clases no jerárquicas necesitan hacer referencia entre sí, elija una que sea débil. El que elijas depende de la situación. Consulte las respuestas a esta pregunta para obtener más información sobre esto.Como regla general, los delegados deben marcarse como
weak
porque la mayoría de los delegados hacen referencia a clases que no les pertenecen. Esto definitivamente es cierto cuando un niño usa un delegado para comunicarse con uno de sus padres. Usar una referencia débil para el delegado es lo que recomienda la documentación . (Pero mira esto también).Los protocolos se pueden utilizar tanto para tipos de referencia (clases) como para tipos de valores (estructuras, enumeraciones). Entonces, en el caso probable de que necesites debilitar a un delegado, debes convertirlo en un protocolo de solo objetos. La forma de hacerlo es agregarlo
AnyObject
a la lista de herencia del protocolo. (En el pasado, esto se hacía usando laclass
palabra clave, peroAnyObject
ahora es preferible ).protocol MyClassDelegate: AnyObject { // ... } class SomeClass { weak var delegate: MyClassDelegate? }
Estudio adicional
Leer los siguientes artículos es lo que me ayudó a comprender esto mucho mejor. También discuten temas relacionados como la unowned
palabra clave y los fuertes ciclos de referencia que ocurren con los cierres.
- Delegar documentación
- Documentación rápida: recuento automático de referencias
- "Débil, fuerte, sin dueño, ¡Dios mío!" - Una guía de referencias en Swift
- Fuerte, débil y sin dueño: clasificando ARC y Swift
Relacionado
- Cómo hacer delegados en Swift
- iOS: Cómo crear delegados débiles en Swift
- Delegación rápida: cuándo usar un puntero débil en delegado
AnyObject
es la forma oficial de utilizar una referencia débil en Swift.
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate: AnyObject {
}
De Apple:
Para evitar ciclos de referencia fuertes, los delegados deben declararse referencias débiles. Para obtener más información sobre referencias débiles, consulte Ciclos de referencia fuertes entre instancias de clase. Marcar el protocolo como de solo clase le permitirá declarar posteriormente que el delegado debe utilizar una referencia débil. Puedes marcar un protocolo como de solo clase heredándolo de AnyObject , como se explica en Protocolos de solo clase.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276