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

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

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()
   }
}

W T H мы должны делать?

Все три предложения, похоже, работают отлично. Какая здесь полная глубина смысла? И что делать?

И в последнем, почему бы вам не сказать что-то вроде [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] 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.