実機 iPhone 8 で試したのですが、バーアイテム・ボタンのどちらも問題なく `Connect`/`Disconnect` の切り替えを何度でも行えますよ。こちらで実装した `updateMotionData(deviceMotion:)` は `print("x: \(deviceMotion.gravity.x)")` するだけの単純なものですが、データの取得がちゃんと切り替わっているのは確認できました。ご提示のコード外の問題の可能性が大きいように感じます。
モーションセンサの@ObservedObjectの関数を
navigationBarItemsで実行すると1度だけ実行できますがが、2回目以降は実行できません。
navigationBarItemsの外側では所望動作です。
なぜでしょう?
struct ContentView: View { @ObservedObject var builtIn = MotionSensor() var body: some View { NavigationView { VStack { Button(action: { if builtIn.isStarted { builtIn.stop() }else{ builtIn.start() } }) { if builtIn.isStarted { Text("Disconnect") .foregroundColor(Color.red) .padding() }else{ Text("Connect") .padding() } } ... 中略 HStack{ Text(String(format:"%6.2f", builtIn.roll * 180.0/Double.pi)).padding() Text(String(format:"%6.2f",builtIn.pitch * 180.0/Double.pi)).padding() Text(String(format:"%6.2f",builtIn.azimuth * 180.0/Double.pi)).padding() } ... 中略 ... }.navigationBarItems(leading: Button(action: { if builtIn.isStarted { builtIn.stop() }else{ builtIn.start() } print("tapped!") }) { if builtIn.isStarted { Text("Disconnect") .foregroundColor(Color.red) .padding() }else{ Text("Connect") .padding() } }) } .navigationViewStyle(StackNavigationViewStyle())
@ObservedObjectは以下です。
import Foundation import CoreMotion class MotionSensor: NSObject, ObservableObject { @Published var isStarted = false let motionManager = CMMotionManager() func start() { // start monitoring sensor data if motionManager.isDeviceMotionAvailable { motionManager.deviceMotionUpdateInterval = 0.1 motionManager.startDeviceMotionUpdates(to: OperationQueue.current!, withHandler: {(motion:CMDeviceMotion?, error:Error?) in self.updateMotionData(deviceMotion: motion!) }) } isStarted = true } func stop() { isStarted = false motionManager.stopDeviceMotionUpdates() } @Published var pitch = 0.0 @Published var roll = 0.0 @Published var azimuth = 0.0 private func updateMotionData(deviceMotion:CMDeviceMotion) { pitch = (deviceMotion.attitude.pitch) roll = (deviceMotion.attitude.roll) azimuth = (deviceMotion.attitude.yaw) }
ありがとうございます。
失礼しました。追記します。
@ObservedObjectのupdateMotionData内をコメントアウトすると
`Connect`/`Disconnect` の切り替えを何度もできますが、
Textが更新されなくなります。
以下を追記
----
var body: some View {
NavigationView {
VStack {
....
HStack{
Text(String(format:"%6.2f", builtIn.roll * 180.0/Double.pi)).padding()
Text(String(format:"%6.2f",builtIn.pitch * 180.0/Double.pi)).padding()
Text(String(format:"%6.2f",builtIn.azimuth * 180.0/Double.pi)).padding()
}
----
@Published var pitch = 0.0
@Published var roll = 0.0
@Published var azimuth = 0.0
private func updateMotionData(deviceMotion:CMDeviceMotion) {
pitch = (deviceMotion.attitude.pitch)
roll = (deviceMotion.attitude.roll)
azimuth = (deviceMotion.attitude.yaw)
}
なるほど、再現できました。「1度だけ実行できる」ではなく値の取得中はナビゲーションバーアイテムのほうだけ反応が鈍いだけのようです。かなりシビアですが、タイミングが合うとバーのほうでも Connect 解除できます。
- `motionManager.deviceMotionUpdateInterval` を `0.2` や `0.5` に和らげると反応するタイミングが改善
- ビューへの値の反映の有無は関係ない(値を表示する `Text` があってもなくても問題が発生する)
- `@Published` なプロパティの値を高頻度で更新していると発生。プロパティが一つでも発生(個数の問題ではない)
うーん、根本的な解決策が分からないですね…………!テクニカルインシデントの残数があればAppleに訊きたいくらいです。
ありがとうございます。
buttonの場合は高頻度であっても所望動作です。
motionManager.deviceMotionUpdateInterval = 0.1
なので、以下に関連していると考えています。
あってそうでしょうか?
https://inon29.hateblo.jp/entry/2020/04/05/161913
あなたの回答
tips
プレビュー