Ios UINavigationViewController中的重场景取消锁定所需时间太长

Ios UINavigationViewController中的重场景取消锁定所需时间太长,ios,uinavigationcontroller,scenekit,Ios,Uinavigationcontroller,Scenekit,我的应用程序使用标准的UINavigationViewController 在某个时刻,用户导航到一个显示SceneKit场景的ViewController 这个场景在内存中非常沉重,因为它有大约6000个几何体,每个几何体都有自己的材质(需要这样) 当用户单击顶部栏上的“上一步”按钮以返回到上一个viewController时,应用程序将正确弹出当前视图控制器并显示下面的视图控制器 但是,在大约4秒钟的时间内,显示的新ViewController的UI冻结 我使用了Instruments Ti

我的应用程序使用标准的UINavigationViewController

在某个时刻,用户导航到一个显示SceneKit场景的ViewController

这个场景在内存中非常沉重,因为它有大约6000个几何体,每个几何体都有自己的材质(需要这样)

当用户单击顶部栏上的“上一步”按钮以返回到上一个viewController时,应用程序将正确弹出当前视图控制器并显示下面的视图控制器

但是,在大约4秒钟的时间内,显示的新ViewController的UI冻结

我使用了Instruments Time Profiler,我可以看到这4秒钟的大部分时间是由这些SceneKit方法占用的:

-[NSConcerteMatable CountByEnumerating with State:对象:计数:]

-[SCNMetalResourceManager\u geometryWillDie:]

-[SCNMetalResourceManager\u materialWillDie:]

这是有道理的,因为有这么多的几何形状和材料


如何解决这种情况,以便在释放重场景时,UI不会被阻塞,无论是从SceneKit角度(使释放更快)还是从UINavigationViewController角度(可能会强制在单独的线程中释放场景?).

我的理解是SceneKit使用自己的后台线程来完成工作,因此它不应该阻塞主线程

主线程的阻塞可能与UINavigationController设置内容动画有关。我在尝试为SCNViews/SCNScenes制作动画时遇到了一些问题,看起来SceneKit和CoreAnimation的协作不是很好

我这里没有完整的上下文,但我可以建议您测试几件事:

  • 您可以尝试使用重场景
    SCNView.scene=[SCNScene scene scene]设置SCNView的场景属性切换到一个新的空场景,以便动画中不涉及重场景,并且SceneKit会在其背景中正确地释放重场景

  • 您可以尝试在视图控制器中保留对重场景的强引用,该视图控制器为重场景准备有问题的视图控制器

    然后,当后一个被弹出并返回到它下面的一个时,弹出的视图控制器及其所有内容都应该被释放,除了重场景,您将有一个对它的引用

    在这里,您可以尝试设置为nil(动画完成后),并且可能会在SceneKit后台线程上正确解除分配

    如果没有,您可以首先删除所有
    heavyScene.rootNode
    子节点、操作等,然后取消分配

    如果这仍然不起作用,可以首先尝试使用递归函数逐个遍历所有节点,并先将其几何体/材质置零,然后取消分配场景本身

  • 使用渲染循环
    -renderer:updateatime:
    方法删除多个帧上的节点(不到一秒钟)。然后您可以确定SceneKit将以其设计的方式处理这些问题

    当用户按下UINavigationController的“后退按钮”时,您必须检测到带有重场景的VC被弹出。然后,比如说20帧(每秒60帧时为1/3秒),在每个帧上移除5%的节点,因此仍然会有很短的延迟,但只有1/3秒,希望不会被注意到

    通过覆盖其
    didMoveToParentViewController:
    方法并检查
    nil
    是否作为
    父参数传递,可以检测到VC被弹出

  • 例如


    谢谢你的回答。我尝试了选项1,结果是4秒的UI冻结发生在弹出动画之前,而不是之后。所以它似乎和内容的UIAnimationController动画无关。我还尝试将重场景设置为新的空场景,而不离开当前的ViewController,UI也会被阻塞。所以我猜主线程上正在发生某种释放。此外,我还尝试使用“EnumerateObjectsSusingBlock”来禁用所有节点的几何体,并且该几何体也会阻止UI。您是否尝试了另一个选项—保留对重场景的引用,以便在转到上一个视图控制器时不会立即取消分配,并且只有在转换完成后,才在后台线程中将其设置为nil。我还添加了一个新的更实用的解决方案,请参见上面答案中的选项3。Hi@Sulevus,是的,在上一个视图控制器中保留对重场景的引用就成功了。非常感谢你的回答!
    - (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
        }
    }