UINavigationViewController中的SceneKit场景太长而无法释放
我的应用程序使用标准的UINavigationViewController。
在某些时候,用户已经导航到显示一个SceneKit场景的ViewController。
这个场景在内存中非常沉重,因为它有大约6000个几何graphics,每个几何graphics都有自己的材质(这需要这样做)。
当用户单击顶部栏的后退button以返回到先前的viewController时,应用程序将正确popup当前的视图控制器并显示下面的视图控制器。
但是,大约4秒钟,新的ViewController的UI显示冻结。
我已经使用了仪器时间分析器,而且我可以看到这些SceneKit方法占用了这4秒钟的很大一部分时间:
– [NSConcreteMapTable countByEnumeratingWithState:objects:count:]
– [SCNMetalResourceManager_geometryWillDie:]
– [SCNMetalResourceManager _materialWillDie:]
这是有道理的,因为有这么多的几何形状和材料。
我怎样才能解决这种情况,以便从SceneKit透视图(快速取消分配)或从UINavigationViewController透视图(可能会强制释放场景以在单独的线程中发生)释放沉重的场景时,UI不会被阻塞? )。
我的理解是,SceneKit使用它自己的后台线程来完成工作,所以它不应该阻塞主线程。
主线程的阻塞可能与UINavigationController将内容animation化有关。 尝试为SCNViews / SCNScenes设置animation时,我遇到了问题,看起来像SceneKit和CoreAnimation协作不好。
我在这里没有完整的上下文,但我可以build议你testing一些事情:
-
你可以尝试设置
scnView.scene = [SCNScene scene];
剧烈的场景scnView.scene = [SCNScene scene];
到视图控制器之前的一个新的空场景被popup,这样重的场景就不参与animation,而且SceneKit正确地将其分配给背景威胁。 -
您可以尝试对View Controller 中的繁重场景进行强有力的参考,从而为繁重的场景准备有问题的视图控制器。
然后,当后者popup,你回到下面的一个,popup的视图控制器及其所有内容应该已经释放,除了沉重的场景,你会有一个参考。
在这里你可以尝试设置为零(animation完成后),并且可能会在SceneKit后台线程上正确释放。
如果没有,你可以先删除所有的
heavyScene.rootNode
子节点,动作等,然后释放。如果这仍然不起作用,您可以先尝试使用recursion函数逐个遍历所有节点,先删除它们的几何体/材质,然后释放场景本身。
-
使用渲染循环
-renderer:updateAtTime:
方法删除多个帧(不到一秒)的节点。 那么你可以确定SceneKit会按照它devise的方式处理它们。当用户按下UINavigationController的“后退button”时,你将不得不检测具有沉重场景的VC被popup。 然后说20帧(60fps的1/3秒),在每一帧中移除5%的节点,所以仍然会有一个短暂的延迟,但是只有1/3的时间,希望不会被察觉。
通过覆盖其
didMoveToParentViewController:
方法并检查是否将nil
作为parent
parameter passing,可以检测到正在popup的VC。
例如
- (void)didMoveToParentViewController:(UIViewController *)parent { if (!parent) { // work that should be done when VC is being removed from parent // maybe set a counter in the VC being popped off to // count down from 20 to 0, -1 at each -update call } }