Swift 陀螺仪偏航、俯仰、横滚

Swift gyroscope yaw, pitch, roll

我正在为我的学校做一个编程主题的项目。我在 Swift 的 Xcode 工作。我想制作一个使用陀螺仪的应用程序。我不知道,但不知何故,它不会在我的 iphone 上运行,因为 Xcode 中的一些错误,我不知道如何 fix.When 我运行程序时说“致命错误:在展开可选值时意外发现 nil (LLDB)” 我项目的主要内容是使用陀螺仪在 iphone 屏幕上以度数显示旋转(偏航、俯仰、滚动)。如果有人帮助我,我将非常感激。先感谢您。

我的 ViewController 中的代码:

import UIKit
import CoreMotion

class ViewController: UIViewController {

    var currentMaxRotX: Double = 0.0
    var currentMaxRotY: Double = 0.0
    var currentMaxRotZ: Double = 0.0

    let motionManager = CMMotionManager()

    @IBOutlet var rotX : UILabel! = nil
    @IBOutlet var rotY : UILabel! = nil
    @IBOutlet var rotZ : UILabel! = nil

    @IBOutlet var maxRotX : UILabel! = nil
    @IBOutlet var maxRotY : UILabel! = nil
    @IBOutlet var maxRotZ : UILabel! = nil


    @IBOutlet weak var RollLabel: UILabel! = nil

    @IBOutlet weak var PitchLabel: UILabel! = nil

    @IBOutlet weak var YawLabel: UILabel! = nil

    override func viewDidLoad() {

        if motionManager.gyroAvailable {

            if !motionManager.gyroActive {
                motionManager.gyroUpdateInterval = 0.2
                motionManager.startGyroUpdates()
                //motionManager = [[CMMotionManager alloc]init]; should I use this ???
                //motionManager.deviceMotionUpdateInterval = 0.2;
                //motionManager.startDeviceMotionUpdates()

                 motionManager.startGyroUpdatesToQueue(NSOperationQueue.currentQueue(), withHandler: {(gyroData: CMGyroData!, error: NSError!)in
                     self.outputRotationData(gyroData.rotationRate)
                     if (error != nil)
                     {
                         println("\(error)")
                     }
                 })      
            }
       } else {
              var alert = UIAlertController(title: "No gyro", message: "Get a Gyro", preferredStyle: UIAlertControllerStyle.Alert)
              alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
              self.presentViewController(alert, animated: true, completion: nil)
    }


     super.viewDidLoad()
    }

    // radians to degrees
    func radians(fromDegrees degrees: Double) -> Double {
        return 180 * degrees / M_PI
    }

    func outputRotationData(rotation:CMRotationRate)
    {
        rotX.text = NSString(format:"Rotation X: %.4f",rotation.x)
        if fabs(rotation.x) > fabs(currentMaxRotX)
        {
            currentMaxRotX = rotation.x
        }

        rotY.text = NSString(format:"Rotation Y: %.4f", rotation.y)
        if fabs(rotation.y) > fabs(currentMaxRotY)
        {
            currentMaxRotY = rotation.y
        }
        rotZ.text = NSString(format:"Rotation Z:%.4f", rotation.z)
        if fabs(rotation.z) > fabs(currentMaxRotZ)
        {
            currentMaxRotZ = rotation.z
        }

        maxRotX.text = NSString(format:"Max rotation X: %.4f", currentMaxRotX)
        maxRotY.text = NSString(format:"Max rotation Y:%.4f", currentMaxRotY)
        maxRotZ.text = NSString(format:"Max rotation Z:%.4f", currentMaxRotZ)

        var attitude = CMAttitude()
        var motion = CMDeviceMotion()
        motion = motionManager.deviceMotion
        attitude = motion.attitude


        YawLabel.text = NSString (format: "Yaw: %.2f", attitude.yaw)    //radians to degress NOT WORKING
        PitchLabel.text = NSString (format: "Pitch: %.2f", attitude.pitch)//radians to degress NOT WORKING
        RollLabel.text = NSString (format: "Roll: %.2f", attitude.roll)//radians to degress NOT WORKING
      }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

在这两行中,您使用的是隐式展开的可选值:您在没有 ?! 的情况下使用它们,但如果它们是 nil,它们会使您的程序崩溃.在这种情况下,motionManager.deviceMotionnil,因为您在该访问之前没有调用 motionManager.startDeviceMotionUpdates()

您的 viewDidLoad 方法是执行此操作的正确位置:

override func viewDidLoad() {

    if motionManager.gyroAvailable {
        motionManager.deviceMotionUpdateInterval = 0.2;
        motionManager.startDeviceMotionUpdates()

        motionManager.gyroUpdateInterval = 0.2
        motionManager.startGyroUpdatesToQueue(NSOperationQueue.currentQueue()) {
           [weak self] (gyroData: CMGyroData!, error: NSError!) in

           self?.outputRotationData(gyroData.rotationRate)
           if error != nil {
               println("\(error)")
           }
        }
    } else {
        // alert message
    }

    super.viewDidLoad()
}

还有一些额外的变化:

  1. 您不需要在 startGyroUpdatesToQueue() 之前调用 startGyroUpdates()
  2. Swift 使用 trailing closures 作为这样的完成处理程序 - 更易于读写。
  3. 为避免引用循环,在完成处理程序中将 self 声明为 weak - 这需要在访问 self.
  4. 时使用可选链接

"guard"、"if let" 和可选链是安全解包可选值的关键,这里是 Swift4 的答案:

let motionManager = CMMotionManager()
    override func viewDidLoad() {
        if motionManager.isGyroAvailable {
            motionManager.deviceMotionUpdateInterval = 0.2;
            motionManager.startDeviceMotionUpdates()

            motionManager.gyroUpdateInterval = 0.2
            guard let currentQueue = OperationQueue.current else { return }
            motionManager.startGyroUpdates(to: currentQueue) { (gyroData, error) in

                // Do Something, call function, etc
                if let rotation = gyroData?.rotationRate {
                    print(rotation)
                    print(rotation.x)
                    print(rotation.y)
                    print(rotation.z)
                }

                if error != nil {
                    print("\(error)")
                }
            }
        }
    }