Куда уходит слабое я?
Я часто делаю это,
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
beep()
}
и в одном приложении мы часто делаем это
tickle.fresh(){
msg in
paint()
}
но если ты сделаешь это
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) {
tickle.fresh(){
msg in
paint()
}
}
конечно вы должны сделать это
let when = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in
tickle.fresh(){
msg in
self?.paint()
}
}
или, может быть, это
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()
}
}
Что нам делать?
Все три предложения, кажется, работают отлично. Какова полная глубина значения здесь? И что делать?
И в заключении, почему бы вам не сказать что-то вроде [weak self?]
, как было?
Примечание - извините, если я не был явным, смысл
func paint() {
paintSomething
let t = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: t) { weak maybe
tickle.fresh(){ weak maybe
guard self != nil else {
print("retired correctly!! hooray! thanks SO!")
return
}
self?.paint()
}
}
}
Итак, мы будем (скажем, запрашивать информацию об игре из облака, а затем) рисовать, ждать две секунды и продолжать делать это снова и снова; но, конечно, вы хотите, чтобы это полностью прекратилось, когда контроллер представления исчезнет.
- Кто-то спрашивает............ Сильная ссылка на слабую ссылку, слабую или сильную ссылку?
Примечание: в моем примере tickle.fresh(){}
просто вызывает синглтон или что-то: как это происходит, он не особенно использует self
, Итак, вы бы сделали это:
func paint() {
paintSomething
let t = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: t) { [weak self] _ in
guard self != nil else {
print("retire early, don't even bother going to the cloud!")
print("thanks, SO!")
return
}
tickle.fresh(){ [weak self] _ in
guard self != nil else {
print("went to the cloud, then got retired!")
print("thanks, SO!")
return
}
self?.paint()
}
}
}
1 ответ
Прежде всего, обратите внимание, что вам обычно не нужно беспокоиться о сохранении циклов с DispatchQueue.main.asyncAfter
, так как закрытие будет выполнено в какой-то момент. Поэтому, слабо ли вы захватить или нет self
вы не будете создавать постоянный цикл хранения (при условии, что tickle.fresh
тоже нет).
Вы положили или нет [weak self]
список захвата на внешней asyncAfter
закрытие полностью зависит от того, хотите ли вы self
сохраняться до вызова закрытия (по истечении установленного вами времени). Если вам не нужно self
чтобы остаться в живых до закрытия называется [weak self]
в, если вы делаете, то не вставляйте его.
Вы положили или нет [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
,