Comment puis-je faire une référence de protocole faible dans Swift ‘pur’ (sans @objc)

weak références weak ne semblent pas fonctionner dans Swift à moins qu’un protocol soit déclaré comme @objc , ce que je ne veux pas dans une application Swift pure.

Ce code donne une erreur de compilation ( weak ne peut pas être appliqué au type MyClassDelegate non-classe):

 class MyClass { weak var delegate: MyClassDelegate? } protocol MyClassDelegate { } 

J’ai besoin de préfixer le protocole avec @objc , puis ça marche.

Question: Quel est le moyen «pur» de réaliser un delegate weak ?

    Vous devez déclarer le type du protocole en tant que class .

     protocol ProtocolNameDelegate: class { // Protocol stuff goes here } class SomeClass { weak var delegate: ProtocolNameDelegate? } 

    D’après ce que je comprends, l’utilisation de class , vous garantissez que ce protocole ne sera utilisé que sur des classes et pas d’autres choses comme des énumérations ou des structures.

    Réponse supplémentaire

    J’ai toujours été confus quant à savoir si les delegates devaient être faibles ou non. Récemment, j’ai appris davantage sur les delegates et quand utiliser des références faibles, alors permettez-moi d’append quelques points supplémentaires à l’intention des futurs téléspectateurs.

    • L’utilisation du mot-clé weak pour but d’éviter les cycles de référence forts (conserver les cycles). Des cycles de référence forts se produisent lorsque deux instances de classe ont des références fortes les unes aux autres. Leurs chiffres de référence n’atteignent jamais zéro, ils ne sont donc jamais libérés.

    • Vous devez seulement utiliser weak si le délégué est une classe. Les structures et les énumérations rapides sont des types de valeur (leurs valeurs sont copiées lorsqu’une nouvelle instance est créée), et non des types de référence, de sorte qu’elles ne provoquent pas de cycles de référence importants.

    • weak références weak sont toujours optionnelles (sinon, vous ne les utiliseriez unowned ) et utilisez toujours var (non let ) pour que l’option puisse être définie sur nil lorsqu’elle est libérée.

    • Une classe parente doit naturellement avoir une référence forte à ses classes enfants et donc ne pas utiliser le mot-clé weak . Quand un enfant veut une référence à son parent, cependant, il devrait en faire une référence faible en utilisant le mot-clé weak .

    • weak devrait être utilisé lorsque vous voulez une référence à une classe que vous ne possédez pas, pas seulement pour un enfant faisant référence à son parent. Lorsque deux classes non hiérarchiques doivent se référencer, choisissez-en une pour être faible. Celui que vous choisissez dépend de la situation. Voir les réponses à cette question pour plus d’informations à ce sujet.

    • En règle générale, les delegates doivent être considérés comme weak car la plupart des delegates font référence à des classes qu’ils ne possèdent pas. Cela est tout à fait vrai lorsqu’un enfant utilise un délégué pour communiquer avec un parent. Cependant, il existe encore des situations où un délégué peut et doit utiliser une référence forte.

    • Les protocoles peuvent être utilisés pour les types de référence (classes) et les types de valeur (structs, enums). Donc, dans le cas probable où vous deviez rendre un délégué faible, vous devez append le mot class clé de class au protocole afin qu’il sache qu’il ne doit être utilisé qu’avec des types de référence.

       protocol MyClassDelegate: class { // ... } class SomeClass { weak var delegate: MyClassDelegate? } 

    Une étude plus approfondie

    La lecture des articles suivants est ce qui m’a aidé à mieux comprendre cela. Ils abordent également des questions connexes telles que le mot-clé non unowned et les forts cycles de référence qui se produisent avec les fermetures.

    • Documentation rapide: comptage automatique des références
    • “Faible, fort, sans propriétaire, oh mon!” – Guide de références en swift
    • Forte, faible et sans propriétaire – Tri ARC et Swift

    en relation

    • Comment faire des delegates à Swift
    • iOS: Comment faire des delegates faibles dans Swift
    • Délégation rapide – Quand utiliser le pointeur faible sur le délégué

    AnyObject est le moyen officiel d’utiliser une référence faible dans Swift.

     class MyClass { weak var delegate: MyClassDelegate? } protocol MyClassDelegate: AnyObject { } 

    De Apple:

    Pour éviter de forts cycles de référence, les delegates doivent être déclarés comme des références faibles. Pour plus d’informations sur les références faibles, voir Cycles de référence forts entre les instances de classe. Marquer le protocole en tant que classe uniquement vous permettra plus tard de déclarer que le délégué doit utiliser une référence faible. Vous marquez un protocole en tant que classe uniquement en héritant d’ AnyObject , comme indiqué dans Protocoles de classe uniquement.

    https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276

    Mise à jour: Il semblerait que le manuel ait été mis à jour et que l’exemple auquel j’ai fait référence ait été supprimé. Voir la réponse à la réponse de @ flainez ci-dessus.

    Original: Utiliser @objc est la bonne façon de le faire, même si vous n’interopérez pas avec Obj-C. Cela garantit que votre protocole est appliqué à une classe et non à une énumération ou à une structure. Voir “Vérification de la conformité du protocole” dans le manuel.

    Apple utilise “NSObjectProtocol” au lieu de “class”.

     public protocol UIScrollViewDelegate : NSObjectProtocol { ... } 

    Cela fonctionne également pour moi et a supprimé les erreurs que je voyais lorsque j’essayais d’implémenter mon propre modèle de délégué.