Здесь я играл с утечками, поэтому я сделал сильный справочный цикл намеренно, чтобы увидеть, что инструменты что-то обнаружат, а я получили неожиданные результаты. Утечка, показанная в Инструментах, конечно, имеет смысл, но случайный сбой немного загадочен (из-за двух фактов, которые я расскажу позже).Использование неавторизованного внутри списка захвата, вызывающего сбой, даже сам блок не выполнен
То, что я здесь класс называется SomeClass
:
class SomeClass{
//As you can guess, I will use this shady property to make a strong cycle :)
var closure:(()->())?
init(){}
func method(){}
deinit {print("SomeClass deinited")}
}
Также у меня есть две сцены, то GameScene
:
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
backgroundColor = .blackColor()
let someInstance = SomeClass()
let closure = {[unowned self] in
someInstance.method() //This causes the strong reference cycle...
self.method()
}
someInstance.closure = closure
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let nextScene = MenuScene(fileNamed: "MenuScene"){
nextScene.scaleMode = .AspectFill
let transition = SKTransition.fadeWithDuration(1)
view?.presentScene(nextScene, transition: transition)
}
}
deinit {print("GameScene deinited")}
func method(){}
}
И, наконец, MenuScene
, который идентичен GameScene
, просто с пустым методом didMoveToView
(он реализован только touchesBegan
).
Воспроизводя Крушение
Катастрофа может воспроизвести путем перехода между сценами в несколько раз. Таким образом, утечка произойдет потому, что someInstance
сохраняется переменной closure
, а переменная closure
сохраняется переменной someInstance
, поэтому у нас есть цикл. Но тем не менее, это не приведет к сбою (он просто протекает). Когда я на самом деле пытаюсь добавить self.method()
внутри закрытия, аварии приложения и я получаю это:
и это:
Точно такие же аварии я могу произвести, если я попытайтесь получить доступ к ссылке unowned
, когда ссылающийся на нее объект освобождается, например. когда закрытие переживает захваченный экземпляр. Это имеет смысл, но это не так (закрытие никогда не выполняется).
Таинственной часть
Таинственная часть является то, что эта авария происходит только на прошивке 9.1 и не на iOS9.3. И еще одна загадочная вещь заключается в том, что приложение неожиданно разбивает , но в основном в течение первых десяти переходов. Кроме того, странная часть - это то, почему она падает, если закрытие никогда не выполняется, или экземпляр, который он захватывает, не доступен (по крайней мере, не мной).
Решение проблемы, но не ответ на вопрос
Конечно аварии можно решить несколькими способами, нарушая цикл, и я знаю, что я должен использовать unowned
только тогда, когда я полностью уверены, что захваченный экземпляр никогда не станет нулевым после инициализации. Но все же, из-за того, что я не выполнил это закрытие вообще, после того, как он пережил сцену, эта авария для меня довольно неудобна. Кроме того, возможно, стоит упомянуть, что сцены успешно деинируются после каждого перехода.
Интересный
Если я использую weak self
внутри списка захвата, приложение не будет врезаться (утечка все еще существует, конечно). Это имеет смысл, потому что, если сцена становится nil
до того, как блок освобожден, доступ к сцене с помощью дополнительной цепочки предотвратит сбой. Но самое интересное в том, что даже если я использую forced unwrapping
как это, он не будет врезаться:
let closure = {[weak self] in
someInstance.method()
self!.method()
}
Что заставляет меня думать ... Цените никаких намеков о том, как отладить это или объяснение о том, что причиной аварии .. .
EDIT:
Вот Github repo
Если это не сбой на 9.3, то это, вероятно, ошибка. Это ваш отчет, кстати? [SR-1006] (https://bugs.swift.org/browse/SR-1006) Похоже на ту же проблему. – Sulthan
@ Sulthan Nope, это не мой отчет об ошибках ... Ну, я начал щедрость, чтобы узнать, может ли кто-нибудь действительно доказать, что это ошибка или нет, и объяснить, что должно быть ожидаемым поведением в этой ситуации. Лично я думаю, что он должен протекать, но не должен терпеть крах, но мы увидим ... – Whirlwind
Я уверен, что он не должен сбой, если вы фактически не выполняете блок. – Sulthan