Куда уходит слабое я?

Я часто делаю это,

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,

Другие вопросы по тегам