【问题标题】: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://stackoverflow.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 是指针,我有这个原因)。

【问题讨论】:

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

标签: iphone uinavigationcontroller ios5


【解决方案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 参数)几乎肯定会在后台线程上调用您传递给其他参数的队列。
  • 天才,天才!感谢您的解释和解决方案。
猜你喜欢
  • 2020-11-08
  • 2012-12-03
  • 2011-03-14
  • 2021-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多