I have an asset loading and caching singleton defined as such:
class AssetLoader {
fileprivate var rootNodes = Dictionary<String, SCNNode>()
static let sharedInstance = AssetLoader()
fileprivate init() {
}
func rootNode(_ named: String) -> SCNNode {
if self.rootNodes[named] != nil {
return self.rootNodes[named]!.clone()
} else {
let scene = SCNScene(named: "art.scnassets/\(named).scn")
self.rootNodes[named] = scene!.rootNode
return self.rootNodes[named]!.clone()
}
}
}
I am using it to make my scene building faster. I'm creating assets from extensions as such:
extension CAAnimation {
class func animationWithScene(named: String) -> CAAnimation? {
unowned let rootNode = AssetLoader.sharedInstance.rootNode(named)
var animation: CAAnimation?
rootNode.enumerateChildNodes({ (child, stop) in
if child.animationKeys.count > 0 {
animation = child.animation(forKey: child.animationKeys.first!)
stop.initialize(to: true)
}
})
return animation
}
}
extension SCNNode {
class func nodeWithScene(named: String) -> SCNNode? {
unowned let rootNode = AssetLoader.sharedInstance.rootNode(named)
let node = SCNNode()
for child in rootNode.childNodes {
node.addChildNode(child)
}
node.eulerAngles = SCNVector3(x: Float(-M_PI_2), y: 0, z: 0)
node.scale = SCNVector3Make(kMeshScale, kMeshScale, kMeshScale)
return node
}
}
Instruments is saying I'm leaking memory like crazy on each calls to clone(). I tried using weak and unowned wherever I could without causing crashes and it doesn't change anything. Anyone has a clue? Is that a bug in SceneKit?
Thanks
If I understand correctly you keep your original nodes in the rootNodes Dictionary of your AssetLoader and return a clone of those in the rootNode func.
My architecture is similar and my issue was the following : when I would remove the cloned node from the scene tree the memory wouldn't get released. Is that your problem?
I fixed the issue by adding an "unload" func in my singleton to nullify the original nodes when removing the cloned nodes from the scene tree. That fixed my memory issues.
With your code that would look something like :
func unloadRootNode(_ named: String) {
rootNodes.removeValue(forKey: named)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With