我一直在AR framework工作一段时间,我正在尝试update from UIAccelerometer (deprecated) to CMMotionManager,但遇到了一些效率问题?
基本上看起来CMMotionManager比UIAccelerometer更大更慢。有没有人以前遇到过CMMotionManager的性能问题?
正如您所见here,我有这个:
accelerometer = [UIAccelerometer sharedAccelerometer];
accelerometer.updateInterval = 0.01;
[accelerometer setDelegate:self];
和
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
rollingZ = (acceleration.z * kFilteringFactor) + (rollingZ * (1.0 - kFilteringFactor));
rollingX = (acceleration.y * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor));
if (rollingZ > 0.0) currentInclination = inc_avg(atan(rollingX / rollingZ) + M_PI / 2.0);
else if (rollingZ < 0.0) currentInclination = inc_avg(atan(rollingX / rollingZ) - M_PI / 2.0);
else if (rollingX < 0) currentInclination = inc_avg(M_PI/2.0);
else if (rollingX >= 0) currentInclination = inc_avg(3 * M_PI/2.0);
}
并且即使在像iPhone 4这样的“旧”设备上也能很好地工作(不是很老但是......)。
但是在使用CMMotionManager尝试完全相同的代码时:
motionManager = [[CMMotionManager alloc] init];
与
[motionManager setAccelerometerUpdateInterval:0.01];
[motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
withHandler: ^(CMAccelerometerData *accelerometerData, NSError *error){
rollingZ = (accelerometerData.acceleration.z * kFilteringFactor) + (rollingZ * (1.0 - kFilteringFactor));
rollingX = (accelerometerData.acceleration.y * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor));
if (rollingZ > 0.0) currentInclination = inc_avg(atan(rollingX / rollingZ) + M_PI / 2.0);
else if (rollingZ < 0.0) currentInclination = inc_avg(atan(rollingX / rollingZ) - M_PI / 2.0);
else if (rollingX < 0) currentInclination = inc_avg(M_PI/2.0);
else if (rollingX >= 0) currentInclination = inc_avg(3 * M_PI/2.0);
}];
数学似乎减慢了它的废话..!我这样说是因为当我删除所有的数学部分时它很有效。
iPhone 5可以正常工作,但iPhone 4S会出现滞后迹象,而iPhone 4只会冻结......
(如果你愿意,我可以给你更多细节,但解释相对复杂)
答案 0 :(得分:7)
我刚遇到同样的问题,你不知道,解决方案是在文档中;)
问题在于块格式。所有教程似乎都支持这种方法,但Apple建议定期轮询CMMotionManager
作为一种更加注重性能的方法。块格式增加了开销。
来自CMMotionManager
班级参考:
要通过定期抽样处理动态数据,应用程序会调用“开始” 不带参数的方法并定期访问运动数据 由属性持有的给定类型的运动数据。这种方法是 适用于游戏等应用的推荐方法。处理 块中的加速度计数据引入了额外的开销,并且大多数 游戏应用程序只对最新的运动数据样本感兴趣 他们渲染一个框架。
那么你想做什么,再次来自文档:
调用startAccelerometerUpdates以定期开始更新 通过读取accelerometerData来访问CMAccelerometerData对象 属性。
沿着这些方向的东西
CMMotionManager *mManager = [(AppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];
[mManager startAccelerometerUpdates];
然后,在您选择的某种定期更新方法中:
CMMotionManager *mManager = [(SEPAppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];
CMAccelerometerData *aData = mManager.accelerometerData;
此解决方案似乎与我在有限的测试中在iPhone 4上的UIAccelerometer
一样有效。
答案 1 :(得分:3)
我使用 CADisplayLink 。
首先,设置 CMMotionManager 实例。
-(void)viewDidLoad
{
[super viewDidLoad];
self.motionManager = [[CMMotionManager alloc]init];
if(self.motionManager.isDeviceMotionAvailable)
{
[self.motionManager startDeviceMotionUpdates];
}
[self setupDisplayLink];
}
其次设置 displaylink 实例,如下所示:
-(void)setupDisplayLink
{
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update:)];
displayLink.frameInterval = 10;// how many frames to skip before next update
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
显示链接是一个连接到设备屏幕的对象,可以使用指定的帧速率运行指定的选择器;更多关于他们here
第三,你应该实现你指定为显示链接选择器的update:方法。
-(void)update:(CADisplayLink *)displayLink
{
// handle new accelerometer data here
CMDeviceMotion *deviceMotion = self.motionManager.deviceMotion;
NSLog(@"Acceleration: %@", deviceMotion.accelerometerData.acceleration);
}