私はこれをよくします
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
beep()
}
そして、1つのアプリでこれを頻繁に行います
tickle.fresh(){
msg in
Paint()
}
しかし、あなたがthis
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
tickle.fresh(){
msg in
Paint()
}
}
もちろん、あなたはしなければなりませんthis
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
tickle.fresh(){
msg in
self?.Paint()
}
}
または、多分this
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
tickle.fresh(){
[weak self] msg in
self?.Paint()
}
}
または多分これ
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
tickle.fresh(){
[weak self] msg in
self?.Paint()
}
}
3つの提案すべてseem完全に動作します。ここでの意味の完全な深さは何ですか?そして、どれをするべきですか?弱い参照への強い参照、弱い参照、または強い参照ですか?あるかどうかそれが問題です!
まず、クロージャーはsomeポイントで実行されるため、一般的にDispatchQueue.main.asyncAfter
の保持サイクルについて心配する必要はないことに注意してください。したがって、self
を弱くキャプチャするかどうかに関係なく、永続的な保持サイクルを作成することはありません(tickle.fresh
もそうではないと想定)。
外側のasyncAfter
クロージャーに[weak self]
キャプチャリストを置くかどうかは、クロージャーが呼び出されるまで(設定した時間の後)self
を保持するかどうかに完全に依存します。クロージャが呼び出されるまで生き続けるためにself
を必要としないなら、[weak self]
を入れてください。そうするなら、入れないでください。
[weak self]
を内側のクロージャー(tickle.fresh
に渡されるもの)に配置するかどうかは、外側のクロージャーでself
を既に弱くキャプチャーしているかどうかによって異なります。まだ持っていない場合は、[weak self]
を配置して、内部のクロージャーが保持しないようにすることができます。ただし、外側のクロージャーがself
を既に弱くキャプチャしている場合、内側のクロージャーはalreadyself
への弱い参照を持つため、[weak self]
を追加します。内側のクロージャーは効果がありません。
要約すると、
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
tickle.fresh { msg in
self.Paint()
}
}
self
は、外側と内側の両方のクロージャーによって保持されます。
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
tickle.fresh { msg in
self?.Paint()
}
}
self
はどちらのクロージャーによっても保持されません。
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
tickle.fresh { [weak self] msg in
self?.Paint()
}
}
上記と同じように、self
は外側のクロージャーによって既に弱くキャプチャされているため、内側のクロージャーに追加の[weak self]
は効果がありません。
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
tickle.fresh { [weak self] msg in
self?.Paint()
}
}
self
は、外側のクロージャーによって保持されますが、内側のクロージャーによって保持されません。
もちろん、self
を外側のクロージャーで保持したくないが、do内側のクロージャーで保持したい場合があります。そのような場合、self
への強い参照を保持するために、外側のクロージャーでローカル変数を宣言できます。その後、内側のクロージャーでキャプチャできます。
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
guard let strongSelf = self else { return }
tickle.fresh { msg in
strongSelf.Paint()
}
}
これで、self
は外側のクロージャーによって保持されなくなりますが、一度呼び出されると、self
がまだ存在する場合、そのクロージャーの割り当てが解除されるまで内側のクロージャーによって保持されます。
に応答して:
弱い参照への強い参照、弱い参照、または強い参照ですか?
弱い参照は、値の型であるオプションとして実装されます。したがって、直接に強い参照を付けることはできません。代わりに、最初にそれをアンラップしてから、基になるインスタンスへの強い参照を取得する必要があります。この場合、単純に強い参照を処理しています(strongSelf
を使用した上記の例とまったく同じです)。
ただし、弱参照がboxedである場合(これはクロージャーキャプチャで発生します-値型はヒープに割り当てられたボックスに入れられます)–そのボックスへの強い参照を実際に持つことができます。この効果は、元のインスタンスへの弱い参照に相当し、目に見えない余分な間接性があります。
実際、これはexactlyです。外側のクロージャーがself
を弱くキャプチャし、内側のクロージャーがその弱い参照を「強くキャプチャ」する例で何が起こるかです。その結果、どちらのクロージャーもself
を保持しません。