【问题标题】:CMMotionManager vs UIAccelerometer efficiencyCMMotionManager 与 UIAccelerometer 效率
【发布时间】:2013-07-15 16:42:07
【问题描述】:

我已经在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 会卡住......

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

【问题讨论】:

    标签: ios performance math uiaccelerometer cmmotionmanager


    【解决方案1】:

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

    问题出在块格式上。所有的教程似乎都支持这种方法,但 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;
    

    根据我所做的有限测试,此解决方案在 iPhone 4 上似乎与 UIAccelerometer 一样有效。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 最后一行:应该是:deviceMotion.accelerometerData.gravity.
      • 我认为 DisplayLink 是更好的解决方案,但是您必须使 displaylink 无效以避免保留循环,因为 displaylink 保留了 runloop。
      猜你喜欢
      • 2013-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      相关资源
      最近更新 更多