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一些事情:

  1. 你可以尝试设置scnView.scene = [SCNScene scene];剧烈的场景scnView.scene = [SCNScene scene]; 到视图控制器之前的一个新的空场景被popup,这样重的场景就不参与animation,而且SceneKit正确地将其分配给背景威胁。

  2. 您可以尝试对View Controller 的繁重场景进行强有力的参考,从而为繁重的场景准备有问题的视图控制器。

    然后,当后者popup,你回到下面的一个,popup的视图控制器及其所有内容应该已经释放,除了沉重的场景,你会有一个参考。

    在这里你可以尝试设置为零(animation完成后),并且可能会在SceneKit后台线程上正确释放。

    如果没有,你可以先删除所有的heavyScene.rootNode子节点,动作等,然后释放。

    如果这仍然不起作用,您可以先尝试使用recursion函数逐个遍历所有节点,先删除它们的几何体/材质,然后释放场景本身。

  3. 使用渲染循环-renderer:updateAtTime:方法删除多个帧(不到一秒)的节点。 那么你可以确定SceneKit会按照它devise的方式处理它们。

    当用户按下UINavigationController的“后退button”时,你将不得不检测具有沉重场景的VC被popup。 然后说20帧(60fps的1/3秒),在每一帧中移除5%的节点,所以仍然会有一个短暂的延迟,但是只有1/3的时间,希望不会被察觉。

    通过覆盖其didMoveToParentViewController:方法并检查是否将nil作为parentparameter 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 } }