Почему [слабое я] работает, но [незаслуженное я] ломается в закрытии Swift?

Это действие SpriteKit повторяется, называя себя закрытием завершения. Он использует закрытие, а не SKAction.repeatActionForever(), потому что ему нужно генерировать случайную переменную каждое повторение:

class Twinkler: SKSpriteNode {
  init() {
    super.init(texture:nil, color:UIColor.whiteColor(), size:CGSize(width:10.0, height:10.0))
    twinkle()
  }
  func twinkle() {
      let rand0to1 = CGFloat(arc4random()) / CGFloat(UINT32_MAX)
      let action = SKAction.fadeAlphaTo(rand0to1, duration:0.1)
      let closure = {self.twinkle()}
      runAction(action, completion:closure)
  }
}

Я думаю, что я должен использовать [unowned self], чтобы избежать сильного опорного цикла с закрытием. Когда я это сделаю:

let closure = {[unowned self] in self.twinkle()}

Он выходит из строя с ошибкой: _swift_abortRetainUnowned. Но если я использую [weak self] вместо:

let closure = {[weak self] in self!.twinkle()}

Выполняется без ошибок. Почему [weak self] работает, но [unowned self] ломается? Должен ли я использовать любой из них здесь?

Объект Twinkler строго упоминается в другом месте программы, как дочерний элемент другого node. Поэтому я не понимаю, как нарушается ссылка [unowned self]. Он не должен быть освобожден.

Я попытался реплицировать эту проблему за пределами SpriteKit с помощью dispatch_after(), но я не смог.

Ответ 1

Это звучит как ошибка. {[unowned self] in self.twinkle()} должен работать тождественно с {[weak self] in self!.twinkle()}

Ответ 2

Если self может быть nil в закрытии, используйте [слабый я].

Если self никогда не будет равным нулю в использовании закрытия, используйте [unowned self].

Если он сбой, когда вы используете [unowned self], тогда self, вероятно, является нулевым в какой-то момент в этом закрытии, поэтому вам нужно будет использовать [слабый я].

Примеры из документации довольно хороши для пояснения при использовании strong, слабых и незанятых в закрытии:

https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/AutomaticReferenceCounting.html

Ответ 3

Недавно я столкнулся с подобной катастрофой. В моем случае иногда у объекта, получившего новую инициализацию, был тот же самый адрес памяти, что и освобожденный. Однако код будет выполнен просто отлично, если два объекта имеют другой адрес памяти.

Итак, это мое сумасшедшее объяснение. Когда быстрая ссылка на закрытие и проверить его список захвата, он проверяет, был ли объект освобожден или нет, если переменная в списке захвата говорит "unowned". Он не выполняет проверку, если объект помечен как "слабый".

Так как объект гарантированно никогда не был ник в закрытии, он никогда не будет там вообще сбой.

Итак, вероятно, ошибка языка. И мое занятие - это использование слабых, а не неодолимых.

Ответ 4

Чтобы не получить ошибку, это должно быть:

let closure = {[weak self] in self?.twinkle()}

not

let closure = {[weak self] in self!.twinkle()}

Восклицательный знак после разворота силы, который выдает ошибку на ноль. Unowned выдаст ошибку, если self - это нуль, как разворачивание силы. При выполнении любого из этих двух вариантов вы должны использовать и защищать, или если инструкция для защиты от нуля.

Ответ 5

Это только мое чтение документации, но здесь теория.

Подобно слабым ссылкам, неопубликованная ссылка не удерживает сильную фиксацию на экземпляре, на который она ссылается. В отличие от слабой ссылки, однако, считается, что неизменная ссылка всегда имеет значение. Из-за этого неизменная ссылка всегда определяется как не необязательный тип. [источник]

Вы сказали, что объект Twinkler сильно привязан как дочерний элемент другого node, но дети SKNode являются неявно развернутыми опциями. Моя ставка заключается в том, что проблема заключается не в том, что self освобождается, но при попытке создать закрытие Swift отказывается при создании неопубликованной ссылки на необязательную переменную. Таким образом, [weak self] - это правый список захвата закрытия, который можно использовать здесь.