一段时间后,SwiftUI 设备运动会卡顿
SwiftUI device motion stutters after some time
我正在尝试使用 SwiftUI iOS 应用程序中的 CoreMotion
框架来移动屏幕上的对象(类似于 Measure 应用程序中的级别功能的想法)。
我有一个 MotionManager
class 来处理设备运动更新:
class MotionManager: ObservableObject {
private var motionManager: CMMotionManager
private var pitch: Double = 0
private var roll: Double = 0
private var yaw: Double = 0
@Published
var x: Double = 0
@Published
var y: Double = 0
init() {
self.motionManager = CMMotionManager()
self.motionManager.deviceMotionUpdateInterval = 1 / 60
self.motionManager.startDeviceMotionUpdates(to: .main) { (deviceMotionData, error) in
guard error == nil else {
print(error!)
return
}
if let attitudeData = deviceMotionData?.attitude {
self.pitch = attitudeData.pitch
self.roll = attitudeData.roll
self.yaw = attitudeData.yaw
}
self.updatePositions()
}
}
private func updatePositions() {
let rollDegrees = self.roll * 180 / .pi
let pitchDegrees = self.pitch * 180 / .pi
self.x = convertAngleToRange(angle: rollDegrees, direction: .x)
self.y = convertAngleToRange(angle: pitchDegrees, direction: .y)
}
}
convertAngleToRange
方法在别处定义,但它本质上是将 pitch/roll 值从弧度映射到像素位置。
我有我的主要观点:
struct ContentView: View {
@StateObject
var motion: MotionManager = MotionManager()
var body: some View {
NavigationView {
NavigationLink(destination: GuideView()) {
EmptyView()
}
}
.environmentObject(motion)
}
}
然后,GuideView
视图:
struct GuideView: View {
@EnvironmentObject
var motion: MotionManager
var body: some View {
GeometryReader { geometry in
Representation(x: $motion.x, y: $motion.y)
.frame(width: geometry.size.width, height: geometry.size.height)
}
.statusBar(hidden: true)
.navigationBarHidden(true)
}
}
最后,包含移动圆的 Representation
视图:
struct Representation: View {
@Binding
var x: Double
@Binding
var y: Double
var body: some View {
GeometryReader { geometry in
Circle()
.fill(Color.gray)
.frame(width: geometry.size.width * 0.5)
.position(
x: geometry.size.width * 0.5 * (CGFloat(x) + 1),
y: geometry.size.height * 0.5 + geometry.size.width * 0.5 * CGFloat(y)
)
}
}
}
这最初工作正常,但一段时间后圆圈的运动变得迟钝并且似乎结结巴巴。如果我四处移动设备,然后将其平放在 table 上,它需要几秒钟才能恢复并静止。
我的想法是 motion.x
和 motion.y
值的发布与刷新显示相结合导致事件累积,这就是它变得非常滞后的原因。我试过减少 MotionManager
class 中的 motionManager.deviceMotionUpdateInterval
但即使在较低的值下它最终也会开始滞后。我想知道每次设备运动更新时是否做了太多事情,但我似乎无法弄清楚如何减少它,因为我仍然需要处理原始俯仰和滚动值以便将它们转换为坐标。
我可以使用一些技巧来避免这个问题,或者至少帮助诊断问题所在。
根据“the docs”,因为处理的事件可能会以很高的速率到达,不推荐使用主操作队列
我正在尝试使用 SwiftUI iOS 应用程序中的 CoreMotion
框架来移动屏幕上的对象(类似于 Measure 应用程序中的级别功能的想法)。
我有一个 MotionManager
class 来处理设备运动更新:
class MotionManager: ObservableObject {
private var motionManager: CMMotionManager
private var pitch: Double = 0
private var roll: Double = 0
private var yaw: Double = 0
@Published
var x: Double = 0
@Published
var y: Double = 0
init() {
self.motionManager = CMMotionManager()
self.motionManager.deviceMotionUpdateInterval = 1 / 60
self.motionManager.startDeviceMotionUpdates(to: .main) { (deviceMotionData, error) in
guard error == nil else {
print(error!)
return
}
if let attitudeData = deviceMotionData?.attitude {
self.pitch = attitudeData.pitch
self.roll = attitudeData.roll
self.yaw = attitudeData.yaw
}
self.updatePositions()
}
}
private func updatePositions() {
let rollDegrees = self.roll * 180 / .pi
let pitchDegrees = self.pitch * 180 / .pi
self.x = convertAngleToRange(angle: rollDegrees, direction: .x)
self.y = convertAngleToRange(angle: pitchDegrees, direction: .y)
}
}
convertAngleToRange
方法在别处定义,但它本质上是将 pitch/roll 值从弧度映射到像素位置。
我有我的主要观点:
struct ContentView: View {
@StateObject
var motion: MotionManager = MotionManager()
var body: some View {
NavigationView {
NavigationLink(destination: GuideView()) {
EmptyView()
}
}
.environmentObject(motion)
}
}
然后,GuideView
视图:
struct GuideView: View {
@EnvironmentObject
var motion: MotionManager
var body: some View {
GeometryReader { geometry in
Representation(x: $motion.x, y: $motion.y)
.frame(width: geometry.size.width, height: geometry.size.height)
}
.statusBar(hidden: true)
.navigationBarHidden(true)
}
}
最后,包含移动圆的 Representation
视图:
struct Representation: View {
@Binding
var x: Double
@Binding
var y: Double
var body: some View {
GeometryReader { geometry in
Circle()
.fill(Color.gray)
.frame(width: geometry.size.width * 0.5)
.position(
x: geometry.size.width * 0.5 * (CGFloat(x) + 1),
y: geometry.size.height * 0.5 + geometry.size.width * 0.5 * CGFloat(y)
)
}
}
}
这最初工作正常,但一段时间后圆圈的运动变得迟钝并且似乎结结巴巴。如果我四处移动设备,然后将其平放在 table 上,它需要几秒钟才能恢复并静止。
我的想法是 motion.x
和 motion.y
值的发布与刷新显示相结合导致事件累积,这就是它变得非常滞后的原因。我试过减少 MotionManager
class 中的 motionManager.deviceMotionUpdateInterval
但即使在较低的值下它最终也会开始滞后。我想知道每次设备运动更新时是否做了太多事情,但我似乎无法弄清楚如何减少它,因为我仍然需要处理原始俯仰和滚动值以便将它们转换为坐标。
我可以使用一些技巧来避免这个问题,或者至少帮助诊断问题所在。
根据“the docs”,因为处理的事件可能会以很高的速率到达,不推荐使用主操作队列