Ответ 1
Прежде всего, обратите внимание, что вам вообще не нужно беспокоиться о сохранении циклов с помощью DispatchQueue.main.asyncAfter
, поскольку закрытие будет выполнено в какой-то момент. Поэтому, если вы слабый захват self
, вы не будете создавать постоянный цикл сохранения (при условии, что tickle.fresh
тоже нет).
Если вы поместите список захвата [weak self]
во внешнее закрытие asyncAfter
, полностью зависит от того, хотите ли вы сохранить self
до тех пор, пока не будет вызвано закрытие (после установленного времени). Если вам не нужно self
, чтобы оставаться в живых до тех пор, пока не будет вызвано замыкание, поместите [weak self]
in, если вы это сделаете, тогда не помещайте его.
Если вы положили [weak self]
на внутреннее закрытие (тот, который прошел до tickle.fresh
), зависит от того, был ли вы уже слабо захвачен self
во внешнем закрытии. Если вы этого не сделали, вы можете положить [weak self]
, чтобы предотвратить внутреннее закрытие. Если, однако, внешнее замыкание уже слабо зафиксировано self
, то внутреннее замыкание уже будет иметь слабую ссылку на self
, поэтому добавление [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()
}
}
То же, что и выше, дополнительный [weak self]
для внутреннего замыкания не действует, поскольку self
уже слабо захвачен внешним замыканием.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
tickle.fresh { [weak self] msg in
self?.paint()
}
}
self
будет сохраняться внешним замыканием, но не внутренним замыканием.
Конечно, может быть, вы не хотите, чтобы self
сохранялся внешним закрытием, но вы хотите, чтобы его сохранили внутреннее закрытие. В таких случаях вы можете объявить локальную переменную во внешнем закрытии, чтобы иметь сильную ссылку на 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
).
Однако, если слабая ссылка помещена в бокс (это происходит с закрытием захвата - тип значения будет помещен в ячейку, выделенную кучей), то у вас действительно может быть сильная ссылка на это поле. Эффект этого эквивалентен слабой ссылке на исходный экземпляр, у вас просто есть невидимый бит дополнительной косвенности.
На самом деле это именно то, что происходит в примере, когда внешнее замыкание слабо захватывает self
, а внутреннее замыкание "сильно фиксирует" эту слабую ссылку. Эффект заключается в том, что ни одна из них не сохраняет self
.