¿Cómo puedo hacer una referencia de protocolo débil en Swift 'puro' (sin @objc)?

Resuelto hnh asked hace 10 años • 8 respuestas

weakLas referencias no parecen funcionar en Swift a menos que se protocoldeclare a como @objc, lo cual no quiero en una aplicación Swift pura.

Este código genera un error de compilación ( weakno 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?

hnh avatar Jun 06 '14 00:06 hnh
Aceptado

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.

flainez avatar Jun 08 '2014 08:06 flainez

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 weakpalabra 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 weaksi 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 .

  • weaklas referencias son siempre opcionales (de lo contrario, usaría unowned) y siempre usan var(not let) para que lo opcional se pueda configurar nilcuando 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 weakpalabra clave. Sin embargo, cuando un niño quiere una referencia a su padre, debe convertirla en una referencia débil utilizando la weakpalabra clave.

  • weakdebe 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 comoweak 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 AnyObjecta la lista de herencia del protocolo. (En el pasado, esto se hacía usando la classpalabra clave, pero AnyObjectahora 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 unownedpalabra 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
Suragch avatar Jan 02 '2016 14:01 Suragch

AnyObjectes 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

Tim Chen avatar Feb 19 '2018 14:02 Tim Chen