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