Je le fais souvent,
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
beep()
}
et dans une application, nous le faisons souvent
tickle.fresh(){
msg in
Paint()
}
mais si vous faites this
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
tickle.fresh(){
msg in
Paint()
}
}
bien sûr vous devez faire this
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
tickle.fresh(){
msg in
self?.Paint()
}
}
ou peut-être this
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
tickle.fresh(){
[weak self] msg in
self?.Paint()
}
}
ou peut-être ceci
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
tickle.fresh(){
[weak self] msg in
self?.Paint()
}
}
Les trois suggestions semblent fonctionnent parfaitement. Quelle est la profondeur de la signification ici? Et que doit-on faire? Est-ce qu'une référence forte à une référence faible, une référence faible ou forte? Être ou ne pas être? C'est la question!
Tout d'abord, notez que vous n'avez généralement pas à vous soucier de la conservation des cycles avec DispatchQueue.main.asyncAfter
, car la fermeture sera exécutée à quelque point . Par conséquent, que vous capturiez ou non faiblement self
, vous ne créerez pas de cycle de conservation permanent (en supposant que tickle.fresh
ne le fait pas non plus.
Que vous mettiez ou non un [weak self]
La liste de capture sur la clôture asyncAfter
extérieure dépend entièrement de la décision de conserver self
jusqu'à ce que la fermeture soit appelée (après le délai que vous avez défini). Si vous n'avez pas besoin de self
pour rester en vie jusqu'à ce que la fermeture soit appelée, mettez [weak self]
in, si vous le faites, alors ne le mettez pas.
Que vous mettiez ou non un [weak self]
sur la fermeture intérieure (celle passée à tickle.fresh
) dépend si vous avez déjà faiblement capturé self
dans la fermeture extérieure. Si vous ne l'avez pas encore fait, vous pouvez mettre [weak self]
afin d'éviter que la fermeture intérieure ne la retienne. Si toutefois, la fermeture extérieure a déjà été faiblement capturée self
, alors la fermeture intérieure aura déjà une référence faible à self
, ajoutant ainsi [weak self]
à la fermeture intérieure n'aura aucun effet.
Donc, pour résumer:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
tickle.fresh { msg in
self.Paint()
}
}
self
sera retenu à la fois par la fermeture extérieure et intérieure.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
tickle.fresh { msg in
self?.Paint()
}
}
self
ne sera pas retenu par les deux fermetures.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
tickle.fresh { [weak self] msg in
self?.Paint()
}
}
Comme ci-dessus, le [weak self]
car la fermeture intérieure n'a aucun effet, car self
est déjà faiblement capturé par la fermeture extérieure.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
tickle.fresh { [weak self] msg in
self?.Paint()
}
}
self
sera retenu par la fermeture extérieure, mais pas par la fermeture intérieure.
Bien sûr, il se peut que vous ne vouliez pas que self
soit retenu par la fermeture extérieure, mais vous faites être retenu par la fermeture intérieure. Dans de tels cas, vous pouvez déclarer une variable locale dans la fermeture externe afin de conserver une référence forte à self
, lorsque vous pourrez alors capturer dans la fermeture interne:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
guard let strongSelf = self else { return }
tickle.fresh { msg in
strongSelf.Paint()
}
}
Maintenant, self
ne sera pas maintenu en vie par la fermeture externe, mais une fois appelé, si self
existera toujours, il sera maintenu en vie par la fermeture interne jusqu'à ce que la fermeture soit désallouée.
En réponse à:
Est-ce qu'une référence forte à une référence faible, une référence faible ou forte?
Les références faibles sont implémentées en tant qu'options, qui sont des types de valeur. Par conséquent, vous ne pouvez pas directement directement - vous devez d'abord le décompresser, puis prendre une référence forte à l'instance sous-jacente. Dans ce cas, vous avez simplement affaire à une référence forte (exactement comme dans l'exemple ci-dessus avec strongSelf
).
Cependant, si une référence faible est encadrée (cela se produit avec la capture de fermeture - le type de valeur sera placé dans une zone allouée au segment de mémoire) - vous pouvez alors en effet avoir une forte référence à cette case. L'effet de ceci est équivalent à une référence faible à l'instance d'origine, vous avez juste un peu invisible d'indirection supplémentaire.
En fait, c’est exactement ce qui se passe dans l’exemple où la fermeture externe capture faiblement self
et la fermeture interne 'capture fortement' qui référence faible. L'effet est qu'aucune fermeture ne retient self
.