4

我已经在AR 框架上工作了一段时间,并且正在尝试从 UIAccelerometer(已弃用)更新到 CMMotionManager,但遇到了一些效率问题?

基本上,CMMotionManager 似乎比 UIAccelerometer 大得多且慢得多。以前有没有人遇到过 CMMotionManager 的性能问题?


正如你在这里看到的,我有这个:

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 将只是冻结...

(如果你愿意,我可以给你更多细节,但解释起来相对复杂)

4

2 回答 2

7

我只是遇到了同样的问题,你不知道吗,解决方案在文档中;)

问题在于块格式。所有的教程似乎都支持这种方法,但 Apple 建议定期轮询这种方法,CMMotionManager因为它是一种更注重性能的方法。块格式增加了开销。

CMMotionManager类参考:

为了通过周期性采样来处理运动数据,应用程序调用一个不带参数的“start”方法,并周期性地访问给定类型运动数据的属性所保存的运动数据。这种方法是游戏等应用程序的推荐方法。在一个块中处理加速度计数据会带来额外的开销,并且大多数游戏应用程序只对渲染帧时的最新运动数据样本感兴趣。

所以你想做什么,再次从文档中:

调用 startAccelerometerUpdates 开始更新并通过读取 accelerometerData 属性定期访问 CMAccelerometerData 对象。

沿着这些思路

CMMotionManager *mManager = [(AppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];

[mManager startAccelerometerUpdates];

然后,在您选择的某种定期更新方法中:

CMMotionManager *mManager = [(SEPAppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];

CMAccelerometerData *aData = mManager.accelerometerData;

UIAccelerometer从我所做的有限测试来看,这个解决方案似乎在 iPhone 4 上同样有效。

于 2013-07-18T06:46:17.047 回答
4

我使用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];
}

显示链接是连接到您的设备屏幕的对象,它可以以指定的帧速率运行指定的选择器;更多关于他们在这里

第三,您应该实施 update: 您指定为显示链接选择器的方法。

-(void)update:(CADisplayLink *)displayLink
{
    // handle new accelerometer data here
    CMDeviceMotion *deviceMotion = self.motionManager.deviceMotion;
    NSLog(@"Acceleration: %@", deviceMotion.accelerometerData.acceleration);
}
于 2013-11-20T12:48:12.660 回答