Reputation: 676
My app is dependent on how the iPhone is held. For many reasons, I need to use the device sensors with CoreMotion
and the .attitude
property. Reading the device's attitude is only used for a few times/seconds when the user will set the configuration for my app.
I have tried both pulling and pushing the motion data. In both cases, I can't figure out how to store the CMAttitude
values in a way that lets me access them elsewhere.
In the code belowβ¦
print
statements inside the manager.startDeviceMotionUpdates
closure work fine..attitude
values outside the closure.TextView
with the attitude data.import SwiftUI
import CoreMotion
let manager = CMMotionManager()
let queue = OperationQueue()
struct ContentView: View {
@State var myAttitude: CMAttitude = CMAttitude()
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
Button(action: {
guard manager.isDeviceMotionAvailable else { return }
manager.startDeviceMotionUpdates(to: queue) { (motion, error) in
guard let motion else {
return
}
let currentAttitude = motion.attitude
myAttitude = currentAttitude
print("π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’")
print("Attitude-Pitch: \(myAttitude)")// βββ These Work Fine!
print("Attitude-Pitch: \(myAttitude.pitch.formatted(.number.precision(.fractionLength(5))))")
print("Attitude-Yaw: \(myAttitude.yaw.formatted(.number.precision(.fractionLength(5))))")
print("Attitude-Roll: \(myAttitude.roll.formatted(.number.precision(.fractionLength(5))))")
print("π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄")
}
}, label: {
Text("Check Your Attitude")
.foregroundStyle(.cyan)
})
Text("Attitude-Pitch: \(myAttitude)") // βββ App Crashes Here!
// Text("Attitude-Pitch: \(myAttitude.pitch.formatted(.number.precision(.fractionLength(5))))")
// Text("Attitude-Yaw: \(myAttitude.yaw.formatted(.number.precision(.fractionLength(5))))")
// Text("Attitude-Roll: \(myAttitude.roll.formatted(.number.precision(.fractionLength(5))))")
}
.padding()
}
}
#Preview {
ContentView(myAttitude: CMAttitude())
}
Upvotes: 1
Views: 96
Reputation: 8407
nil
as a default
@State var myAttitude: CMAttitude?
and update the states in the main queue:
DispatchQueue.main.async {
myAttitude = currentAttitude
}
Upvotes: -1
Reputation: 29614
There are 2 issues with your code
@State
should always be marked private
because the memberwise initializer is considered unsafe.https://developer.apple.com/documentation/swiftui/state
CMAttitude()
compiles, it is not documented so you should not use it. It comes from NSObject
it doesn't really belong to CMAttitude
(This is a bug).https://developer.apple.com/documentation/coremotion/cmattitude
Once you correct both those issues your code will no longer crash.
import SwiftUI
import CoreMotion
let manager = CMMotionManager()
let queue = OperationQueue()
struct SampleAttitudeView: View {
//State should always be private.
// Mark optional
@State private var myAttitude: CMAttitude?
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
Button(action: {
guard manager.isDeviceMotionAvailable else { return }
manager.startDeviceMotionUpdates(to: queue) { (motion, error) in
guard let motion else {
return
}
let currentAttitude = motion.attitude
myAttitude = currentAttitude
print("π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’π’")
print("Attitude-Pitch: \(myAttitude!)")// βββ These Work Fine!
print("Attitude-Pitch: \(myAttitude!.pitch.formatted(.number.precision(.fractionLength(5))))")
print("Attitude-Yaw: \(myAttitude!.yaw.formatted(.number.precision(.fractionLength(5))))")
print("Attitude-Roll: \(myAttitude!.roll.formatted(.number.precision(.fractionLength(5))))")
print("π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄π΄")
}
}, label: {
Text("Check Your Attitude")
.foregroundStyle(.cyan)
})
// Show the attitude once it is available.
if let myAttitude {
Text("Attitude-Pitch: \(myAttitude)") // βββ App Crashes Here!
Text("Attitude-Pitch: \(myAttitude.pitch.formatted(.number.precision(.fractionLength(5))))")
Text("Attitude-Yaw: \(myAttitude.yaw.formatted(.number.precision(.fractionLength(5))))")
Text("Attitude-Roll: \(myAttitude.roll.formatted(.number.precision(.fractionLength(5))))")
} else {
Text("Waiting for Attitude")
}
}
.padding()
}
}
#Preview {
SampleAttitudeView()
}
Upvotes: 0