为啥 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,为啥它受到保护?