为什么用ARSCNView关闭ViewController时UI会冻结?

时间:2019-02-03 19:12:51

标签: swift memory-leaks arkit freeze ui-thread

我正在运行放置KitKit节点的ARKit会话。对于每个节点,我都将实例化一个新的视图控制器,并将其视图作为该节点的内容进行传递,如下所示:

func createTextNode(anchor: ARCardAnchor) -> SCNNode? {
    let plane = SCNPlane()
    plane.height = 0.5
    plane.width = 0.5

    let sb = UIStoryboard(name: "Main", bundle: nil)
    let fCVC = sb.instantiateViewController(withIdentifier: "CardViewController") as! CardViewController


    plane.firstMaterial?.diffuse.contents = fCVC.view
    let cardNode = SCNNode(geometry: plane)
    cardNode.constraints = [billboardConstraint]
    return cardNode
}

我正在使用以下ARSCNViewDelegate方法和自定义的ARCardAnchor(ARAnchor的子类)将节点添加到场景中:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

    if let fcanchor = anchor as? ARCardAnchor {
        DispatchQueue.main.async {
            guard let n = self.nodeCreator.createTextNode(anchor: fcanchor) else { return }
            node.addChildNode(n)

        }
    }
}

到目前为止,一切正常,节点放置在3D空间中。但是,当我导航回到上一个View Controller时,UI冻结了,我无法执行任何操作。 我已经尝试过使用这样的放松节奏

@IBAction func goBackToPrevious(_ sender: Any) {
    sceneView.session.pause()
    self.performSegue(withIdentifier: "unwindToPrevious", sender: self)
}

和一个导航控制器,我将AR场景控制器从堆栈中弹出。每次冻结先前的视图控制器时。 Xcode中没有错误,该应用程序保持运行。 如果我等待大约。 2分钟后,我可以再次使用屏幕。如果我不将带有视图控制器的节点添加到我的AR场景中,那么一切都会很好。我唯一的解释是,添加节点时,UIThread不堪重负,因为它在某处造成了巨大的内存泄漏(尽管经过10个小时的调试,我仍然没有发现)。有没有人有过类似的经历,可以告诉我如何解决?我该怎么做才能调试并确保顺利导航?

2 个答案:

答案 0 :(得分:1)

问题是我将自定义UIViewController视图直接分配给节点的平面。我的假设是,由于视图控制器持有对我在场景中其他地方使用的对象的引用,因此创建了引用周期。我通过捕获视图的图像并将其分配给节点来解决它。 似乎直接将UIViews分配给节点通常是一种危险的做法,因为它会引发参考循环。 也许在内存问题和/或SceneKit方面更有资格的人可以对此发表意见。

答案 1 :(得分:0)

 /* I think whenever UIView are directly attached to SCNMaterial and 
 that SCNMaterial to SCNNode. SCNMaterial are still being used when 
 previous screen is visited. By resetting ARSCNView seems to resolve   
 the issue. */

 //try this 
 override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    //reset ARSCNView before going back to previous screen
    self.sceneView = ARSCNView()
 }
相关问题