89 votes

D'où la faiblesse de l'auto aller?

J'ai souvent ce faire,

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
   beep()
}

et en une seule application, nous faisons souvent ce

tickle.fresh(){
    msg in
    paint()
}

mais si vous faites ce

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
   tickle.fresh(){
      msg in
      paint()
   }
}

bien sûr, vous avez à faire cela

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
   tickle.fresh(){
      msg in
      self?.paint()
   }
}

ou, peut-être que ce

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
   tickle.fresh(){
      [weak self] msg in
      self?.paint()
   }
}

ou peut-être ce

let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
   tickle.fresh(){
      [weak self] msg in
      self?.paint()
   }
}

W T H devons-nous faire?

Tous les trois suggestions semble fonctionner à la perfection. Quelle est la profondeur de sens ici? Et qui doit-on faire? Est une référence forte à une référence faible, une faible ou une forte référence? Être ou ne pas être? C'est la question!

209voto

Hamish Points 42073

Tout d'abord, notez que vous n'avez généralement pas besoin de s'inquiéter à propos de conserver cycles, DispatchQueue.main.asyncAfter, que la fermeture sera exécuté sur certains point. Donc si vous avez ou non faiblement capture self, vous ne serez pas en création permanente d'un cycle de conserver (en supposant que l' tickle.fresh n'a pas également).

Si ou pas vous mettre un [weak self] liste de capture sur l'extérieur, asyncAfter fermeture dépend entièrement de vous souhaitez self à être conservées jusqu'à la clôture est appelé (après le temps que vous). Si vous n'avez pas besoin d' self pour rester en vie jusqu'à la clôture est appelé, mis [weak self] en, si vous le faites, alors ne pas le mettre.

Si ou pas vous mettre un [weak self] sur la partie intérieure de la clôture, l'on est passé de tickle.fresh) dépend si vous avez déjà faiblement capturé self à l'extérieur de la clôture. Si vous n'avez pas, alors vous pouvez mettre [weak self] afin de prévenir l'intérieur de la fermeture de son maintien. Si toutefois, à l'extérieur de fermeture a déjà faiblement capturé self, puis l'intérieur de la fermeture va déjà avoir une faible référence à l' self, donc l'ajout d' [weak self] à l'intérieur de la fermeture n'aura aucun effet.

Donc, pour résumer:


DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
   tickle.fresh { msg in
      self.paint()
   }
}

self sera conservé par à la fois l'extérieur et l'intérieur de la clôture.


DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
   tickle.fresh { msg in
      self?.paint()
   }
}

self ne seront pas conservées par la fermeture.


DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
   tickle.fresh { [weak self] msg in
      self?.paint()
   }
}

Même que ci-dessus, la plus - [weak self] pour l'intérieur de la fermeture n'a pas d'effet, comme self est déjà faiblement captée par l'extérieur de la clôture.


DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
   tickle.fresh { [weak self] msg in
      self?.paint()
   }
}

self sera conservé par l'extérieur de fermeture, mais pas à l'intérieur de la clôture.


Bien sûr, il pourrait être que vous ne voulez pas self à être conservé par l'extérieur de fermeture, mais vous ne voulez qu'il soit conservé par l'intérieur de la clôture. Dans de tels cas, vous pouvez déclarer une variable locale à l'extérieur de fermeture, afin de maintenir une référence forte à l' self,, où vous pouvez alors saisir dans l'intérieur de la fermeture:

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
   guard let strongSelf = self else { return }
   tickle.fresh { msg in
      strongSelf.paint()
   }
}

Maintenant, self de ne pas être maintenu en vie par l'extérieur de fermeture, mais une fois qu'il est appelé, si self existe toujours, il sera maintenu en vie par l'intérieur de la fermeture jusqu'à ce que la fermeture a été libéré.


En réponse à:

Est une référence forte à une référence faible, une faible ou une forte référence?

Références faibles sont mis en œuvre comme des options, qui sont des types de valeur. Par conséquent, vous ne pouvez pas directement avoir une référence forte à l'un – à la place, vous devez d'abord ouvrir le cadeau, puis de prendre une référence forte à l'instance sous-jacente. Dans ce cas, vous êtes tout simplement traitant avec une référence forte (exactement comme mon exemple ci-dessus avec strongSelf).

Toutefois, si une référence faible est en boîte (ce qui arrive avec la fermeture de capture – le type de valeur doit être mis dans un segment de mémoire allouée à cocher) – alors vous pouvez en effet avoir une forte référence à cette zone. L'effet de ceci est équivalent à une faible référence à l'instance originale, vous avez juste un invisible peu plus d'indirection.

En fait, c'est exactement ce qui se passe dans l'exemple où l'extérieur fermeture faiblement capture self et l'intérieur de la fermeture "fortement capture" qui référence faible. L'effet est que ni la fermeture conserve self.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X