Как использовать Core Motion для вывода данных магнитометра с помощью SwiftUI? - PullRequest
0 голосов
/ 13 октября 2019

У меня проблемы с выводом данных для магнитометра, акселерометра и гироскопа с использованием Core Motion с SwiftUI. Я предполагаю, что моя проблема как-то связана с startMagnetometerUpdates ().

Я пытался использовать исходный код, найденный здесь, при переполнении стека, а также в GitHub / google. Проблема в том, что весь код, который я нахожу, использует UIKit вместо SwiftUI. Возможно ли реализовать это без использования UIKit?

import CoreMotion

let motionManager = CMMotionManager()
var x = 0.0; var y = 0.0; var z = 0.0

    func magnet() {
  motionManager.magnetometerUpdateInterval = 1/60
  motionManager.startMagnetometerUpdates()
if let magnetometerData = motionManager.magnetometerData {
    x = magnetometerData.magneticField.x
    y = magnetometerData.magneticField.y
    z = magnetometerData.magneticField.z
}
}

struct Magnetometer: View {
        var body: some View {
            VStack {
                Text("Magnetometer Data")
                Text("X: \(x)")
                Text("Y: \(y)")
                Text("Z: \(z)")
            }
        }
    }

struct Magnetometer_Previews: PreviewProvider {
    static var previews: some View {
        Magnetometer()
    }
}

Выходные данные должны просто отображать значения x, y и z для датчика и обновляться с интервалом 1/60. Токовый выход составляет 0,00000 для каждого значения, потому что я уже установил для каждой переменной значение 0.

Ответы [ 2 ]

0 голосов
/ 14 октября 2019

У вас есть пара проблем с вашим кодом.

Ваша первая проблема заключается в том, что вам нужна связь между данными модели и вашим представлением. При создании привязки представление будет обновляться автоматически, когда модельизменения.

Вторая проблема заключается в том, что вы получаете доступ к данным магнитометра только один раз через motionManager.magnetometerData, а не настраиваете закрытие для мониторинга обновлений через startMagnetometerUpdates(to:withHandler:).

Вы можете использовать ObservableObject из Combine framework и @ObservedObject, по вашему мнению, для создания соответствующей привязки.

Начните с создания класса для переноса вашего менеджера движений:

import Foundation
import Combine
import CoreMotion

class MotionManager: ObservableObject {

    private var motionManager: CMMotionManager

    @Published
    var x: Double = 0.0
    @Published
    var y: Double = 0.0
    @Published
    var z: Double = 0.0


    init() {
        self.motionManager = CMMotionManager()
        self.motionManager.magnetometerUpdateInterval = 1/60
        self.motionManager.startMagnetometerUpdates(to: .main) { (magnetometerData, error) in
            guard error == nil else {
                print(error!)
                return
            }

            if let magnetData = magnetometerData {
                self.x = magnetData.magneticField.x
                self.y = magnetData.magneticField.y
                self.z = magnetData.magneticField.z
            }

        }

    }
}

Этот класс соответствуетObservableObject и @Publish его три свойства, x, y и z.

Простое присвоение новых значений этим свойствам в закрытии обновления магнитометра приведет к тому, что издатель запустит и обновит любые наблюдатели.

Теперь, по вашему мнению, вы можете объявить @ObservedObject для вашего класса менеджера движения и связать свойства.

struct ContentView: View {

    @ObservedObject
    var motion: MotionManager

    var body: some View {
        VStack {
            Text("Magnetometer Data")
            Text("X: \(motion.x)")
            Text("Y: \(motion.y)")
            Text("Z: \(motion.z)")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(motion: MotionManager())
    }
}

Обратите внимание, что вам нужно будет передать inпозиция MotionManager в вашем SceneDelegate.swift файле:

let contentView = ContentView(motion: MotionManager())
0 голосов
/ 13 октября 2019

Вы можете использовать Combine для создания класса для предоставления данных:

import Combine

public class MagneicFieldProvider: NSObject, ObservableObject {

    public let objectWillChange = PassthroughSubject<CMMagneticField,Never>()

    public private(set) var magneticField: CMMagneticField = CMMagneticField() {
        willSet {
            objectWillChange.send(newValue)
        }
    }

    deinit {
        motionManager.stopMagnetometerUpdates()
    }

    private let motionManager: CMMotionManager

    public override init(){
        self.motionManager = CMMotionManager()
        super.init()
        motionManager.magnetometerUpdateInterval = 1/60
    }

    public func startUpdates() {
        motionManager.startMagnetometerUpdates(to: OperationQueue.main) { this, that in
            if let magneticField = self.motionManager.magnetometerData?.magneticField {
                self.magneticField = magneticField
            }
        }
    }
}

, а затем использовать его в своем представлении:

struct MagnetometerView: View {

    @ObservedObject var magnetometer = MagneicFieldProvider()

    var body: some View {
        VStack(alignment: .leading) {
            Text("Magnetometer Data")
            Text("X: \(magnetometer.magneticField.x)")
            Text("Y: \(magnetometer.magneticField.y)")
            Text("Z: \(magnetometer.magneticField.z)")
        }   .onAppear(perform: { self.magnetometer.startUpdates() })
    }
}
...