Проблема
Ранее я обнаружил, что использование памяти в моей игре увеличивалось только при перемещении тайлов, но никогда больше не уменьшалось.Исходя из этого, я мог сказать, что произошла утечка памяти.
Затем я начал использовать инструменты XCode, к которым я очень новичок.Итак, я следовал многим вещам из этой статьи , особенно Recording Options
, а затем я установил режим, чтобы показать Call Tree
.
Результаты инструментов
В чем мне нужна помощь?
У меня есть две функции, которые просто перемещают все плитки вдоль этой строки / столбца, а затем клонируют плитку вконец (с использованием node.copy()
), чтобы все могло «зацикливаться», отсюда и название проекта.
Мне кажется, что клонирование плитки может вызывать некоторый цикл хранения, однако оно сохраняется в переменной внутри функцииобъем.После запуска SKAction
на клоне я удаляю плитку со сцены, используя copiedNode.removeFromParent()
.
Так что может быть причиной этой утечки памяти?Могу ли я искать не в том месте?
Код
Я сократил этот код до того, что считаю необходимым.
Объявление в верхней части класса:
/// Delegate to the game scene to reference properties.
weak var delegate: GameScene!
/// All the cloned tiles currently on the board.
private var cloneTiles = [SKSpriteNode]()
Клонирование плитки в движущихся плитках выполняет следующие функции:
/// A duplicate of the current tile.
let copiedNode = currentTile.node.copy() as! SKSpriteNode // Create copy
cloneTiles.append(copiedNode) // Add as a clone
delegate.addChild(copiedNode) // Add to the scene
let copiedNodeAction = SKAction.moveBy(x: movementDifference, y: 0, duration: animationDuration) // Create the movement action
// Run the action, and then remove itself
copiedNode.run(copiedNodeAction) {
self.cloneTiles.remove(at: self.cloneTiles.firstIndex(of: copiedNode)!)
copiedNode.removeFromParent()
}
Функция немедленного перемещения плиток:
/// Move all tiles to the correct location immediately.
private func moveTilesToLocationImmediately() {
// Remove all clone tiles
cloneTiles.forEach { $0.removeFromParent() }
cloneTiles.removeAll()
/* Moves tiles here */
}
Есть ли что-то, что мне нужно объявитькак weak var
или как?Я знаю, как происходят циклы сохранения, но не понимаю, почему он существует в этом коде, поскольку я удаляю клонированную ссылку на плитку из массива cloneTiles
.
Примерно там, где происходит утечка (помогаетMark Szymczyk
)
Вот что произошло после того, как я дважды щелкнул по функции перемещения плиток в стеке вызовов (см. Его ответ ниже):
Это подтверждает, что утечка памяти как-то вызвана клоном узла, но я до сих пор не знаю, почему этот узел все еще сохраняется после его удаления из массива cloneTiles
и сцены.Может быть, у узла по какой-то причине возникли проблемы с удалением со сцены?
Пожалуйста, оставьте любые советы или вопросы по этому поводу, чтобы эту проблему можно было решить!
Подробнеерасследование
Я сейчас пытаюсь разобраться с инструментами Xcode, но я все еще очень стараюсь найти эту утечку памяти.Вот панель утечек, которая может помочь:
Даже после попытки [weak self]
Мне все еще не повезло:
Даже история утечек по-прежнему выглядит так же, как [weak self]
в закрытии.
Продолжаем пытаться разрешить ссылочный цикл
В настоящее время @matt
помогает мне решить эту проблему.Я изменил несколько строк кода, добавив такие вещи, как [unowned self]
:
// Determine if the tile will roll over
if direction == .up && movementDifference < 0 || direction == .down && movementDifference > 0 {
// Calculate where the clone tile should move to
movementDifference -= rollOverDistance
/// A duplicate of the current tile.
let copiedNode = currentTile.node.copy() as! SKSpriteNode // Create copy
cloneTiles.append(copiedNode) // Add as a clone
delegate.addChild(copiedNode) // Add to the scene
let copiedNodeAction = SKAction.moveBy(x: 0, y: movementDifference, duration: animationDuration) // Create the movement action
// Run the action, and then remove itself
copiedNode.run(copiedNodeAction) { [unowned self, copiedNode] in
self.cloneTiles.remove(at: self.cloneTiles.firstIndex(of: copiedNode)!).removeFromParent()
}
// Move the original roll over tile back to the other side of the screen
currentTile.node.position.y += rollOverDistance
}
/// The normal action to perform, moving the tile by a distance.
let normalNodeAction = SKAction.moveBy(x: 0, y: movementDifference, duration: animationDuration) // Create the action
currentTile.node.run(normalNodeAction) { [unowned self] in // Apply the action
if forRow == 1 { self.animationsCount -= 1 } // Lower animation count for completion
}
К сожалению, я не смог сделать свойство copiedNode
weak
, поскольку оно всегда было бы мгновенно nil
,и unowned
вызвал сбой при чтении ссылки после освобождения.Вот также график Cycles & Roots
, если это полезно:
Спасибо за любую помощь!