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


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

Ce code donne une erreur de compilation (weak ne peut pas être appliqué à un type autre que la classe MyClassDelegate):

class MyClass {
  weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate {
}

Je dois préfixer le protocole avec @objc, alors ça marche.

Question: Quel est le moyen «pur» rapide d'accomplir un weak  delegate?


449
2018-06-05 17:16


origine


Réponses:


Vous devez déclarer le type du protocole comme class.

protocol ProtocolNameDelegate: class {
    // Protocol stuff goes here
}

class SomeClass {
    weak var delegate: ProtocolNameDelegate?
}

Ma compréhension est que l'aide class, vous garantissez que ce protocole sera utilisé uniquement sur les classes et pas d'autres choses comme des enum ou des structs.


829
2018-06-08 08:35



Réponse supplémentaire

J'étais toujours confus quant à savoir si les délégués devraient être faibles ou non. Récemment, j'ai appris davantage sur les délégués et quand utiliser des références faibles, alors permettez-moi d'ajouter quelques points supplémentaires ici pour les futurs téléspectateurs.

  • Le but de l'utilisation du weak Le mot-clé permet d'éviter les cycles de référence forts (conserver les cycles). Les cycles de référence forts se produisent lorsque deux instances de classe ont de fortes références les unes aux autres. Leurs chiffres de référence ne vont jamais à zéro, donc ils ne sont jamais désaffectés.

  • Vous avez seulement besoin d'utiliser weak si le délégué est une classe. Les structures et les énumérations Swift 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 rendent pas référence cycles.

  • weak les références sont toujours optionnelles (sinon vous utiliseriez unowned) et utilisez toujours var (ne pas let) de sorte que l'option peut être réglé sur nil quand il est désaffecté.

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

  • weak devrait être utilisé quand vous voulez une référence à une classe que vous ne possédez pas, pas seulement pour un enfant référençant 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 en savoir plus

  • En règle générale, les délégués doivent être marqués comme weak parce que la plupart des délégués se réfèrent à des cours 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 y a encore certaines situations où un délégué peut et doit utiliser une référence forte.

  • Les protocoles peuvent être utilisés pour les deux types de référence (classes) et types de valeur (structs, enums). Donc, dans le cas probable où vous devez rendre un délégué faible, vous devez ajouter le class mot-clé au protocole pour 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 discutent également de questions connexes telles que unownedmot-clé et les forts cycles de référence qui se produisent avec les fermetures.

en relation


190
2018-01-02 14:20



AnyObject est la façon officielle d'utiliser une référence faible dans Swift.

class MyClass {
    weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate: AnyObject {
}

D'Apple:

Pour éviter des cycles de référence importants, les délégués doivent être déclarés comme   références faibles. Pour plus d'informations sur les références faibles, voir   Forts cycles de référence entre les instances de classe. Marquer le protocole   comme classe seule vous permettra plus tard de déclarer que le délégué doit   utiliser une référence faible. Vous marquez un protocole comme étant de classe uniquement   hériter de AnyObject, comme indiqué dans les 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


14
2018-02-19 14:18



Mettre à jour:  Il semble que le manuel ait été mis à jour et que l’exemple dont je parlais a été supprimé. Voir la réponse à la réponse de @ flainez ci-dessus.

Original: Utiliser @objc est le bon moyen 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.


8
2018-06-07 06:26



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é.


-6
2018-04-19 16:49