为啥 popToRootViewContoller 会冻结或需要很长时间才能执行?

Posted

技术标签:

【中文标题】为啥 popToRootViewContoller 会冻结或需要很长时间才能执行?【英文标题】:Why does popToRootViewContoller either freezes or takes a long time to perform?为什么 popToRootViewContoller 会冻结或需要很长时间才能执行? 【发布时间】:2011-12-05 16:59:17 【问题描述】:

我已经用导航控制器设置了一些视图。当我摇晃手机时,我希望能够回到原来的视图。首先,这是我在 AppDelegate 中的代码 sn-p:

- (void)startAccelerometerUpdates


[motionManager startDeviceMotionUpdatesToQueue:queue withHandler:^(CMDeviceMotion *motion, NSError *error) 
    // based from 
    // http://***.com/questions/5214197/simple-iphone-motion-detect/5220796#5220796
    float accelerationThreshold = 1; // or whatever is appropriate - play around with   different values
    CMAcceleration userAcceleration = motion.userAcceleration;
    if (fabs(userAcceleration.x) > accelerationThreshold || 
        fabs(userAcceleration.y) > accelerationThreshold || 
        fabs(userAcceleration.z) > accelerationThreshold) 



        if(!self->isRoot) 
            NSLog(@"Stopping motion manager");
            [motionManager stopDeviceMotionUpdates];
            NSLog(@"popping to top view controller");
            [navcon popToRootViewControllerAnimated:YES];
            NSLog(@"Done popping");
        

    

];


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

   .....

   motionManager = [[CMMotionManager alloc] init];
   motionManager.deviceMotionUpdateInterval = .5;

   isRoot = malloc(sizeof(BOOL));
   self->isRoot = NO;
   [self startAccelerometerUpdates];

   [navcon pushViewController:main animated:NO];
   ....

我期待对 popToRoot 的调用会立即生效。但是,它需要大约 30 秒。有趣的是,您可以按下以手动返回上一页的顶部按钮此时不起作用。手机似乎做了很多工作来冻结按钮。所以,我肯定在这里做错了什么。

它认为我可能会多次调用 popToRootViewController,所以我添加了一个检查“isRoot”,正如您在代码中看到的那样(请不要分心为什么 BOOL 是指针,我有这个原因)。

【问题讨论】:

在这里显示您的实际日志可能很有用。 日志就是这三行...停止、弹出、完成我在代码中的操作。代码通过方法运行没有问题。 【参考方案1】:

您的运动处理程序块似乎打算在后台队列上运行。 UIKit 方法(如 popToRootViewController)只能在主线程上调用,当您不遵守该规则时的行为通常与您所描述的相似。

-performSelectorOnMainThread:withObject:waitUntilDone 是确保您的 UIKit 代码在主线程上运行的最简单方法,但由于 -popToRootViewControllerAnimated: 采用非对象参数,因此需要更多工作。最简单的方法是添加另一个不带参数的方法:

-(void)popToRootView 
    [navcon popToRootViewControllerAnimated:YES];

然后更新您的块以在主线程上调用该方法:

if(!self->isRoot) 
    [motionManager stopDeviceMotionUpdates];
    [self performSelectorOnMainThread:@selector(popToRootView) withObject:nil waitUntilDone:NO];

【讨论】:

它是从 didFinishLaunchingWithOptions 调用的(我已经更新了我的代码)。我不确定这是后台线程还是主线程。抱歉,这里对 ios 很陌生 :) 方法-startAcceleratorUpdates 可能在主线程上调用,但您定义为回调的块(-startDeviceMotionUpdatesToQueue:withHandler 的 withHandler 参数)几乎肯定会在后台线程上调用您传递给其他参数的队列。 天才,天才!感谢您的解释和解决方案。

以上是关于为啥 popToRootViewContoller 会冻结或需要很长时间才能执行?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 glTranslatef?为啥不直接更改渲染坐标?

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?