[英]How to display data from Observable Object with high performances in swiftUI?
在我的指南针应用程序中,我显示航向但性能不高:当我快速转动设备时,所有度数都没有显示。 我搜索了与 Apple 的 natif compass 应用程序相同的性能。 例如,当角度超过 359 到 0 度时,我会振动以通知用户。 但有时振动不会出现。
我的 LocationProvider 类:
import SwiftUI
import CoreLocation
import Combine
public class LocationProvider: NSObject, CLLocationManagerDelegate, ObservableObject {
private let locationManager: CLLocationManager
public let heading = PassthroughSubject<CGFloat, Never>()
@Published var currentHeading: CGFloat {
willSet {
heading.send(newValue)
}
}
public override init() {
currentHeading = 0
locationManager = CLLocationManager()
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingHeading()
locationManager.requestWhenInUseAuthorization()
}
public func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
self.currentHeading = CGFloat(newHeading.trueHeading)
}
}
我的内容视图:
import SwiftUI
import CoreLocation
struct ContentView: View {
@ObservedObject var location: LocationProvider = LocationProvider()
@State var angle: CGFloat = 0
var body: some View {
VStack {
Text(String(Double(-self.location.currentHeading + 360).stringWithoutZeroFraction) + "°")
.font(.system(size: 80))
}
.onReceive(self.location.heading) { heading in
compassTapticFeedback(-heading + 360)
}
}
}
public extension Double {
var stringWithoutZeroFraction: String {
return String(format: "%.0f", self)
}
}
// Taptic feednack
func tapticFeedback(_ type: String) {
switch type {
case "heavy":
let tapticFeedback = UIImpactFeedbackGenerator(style: .heavy)
tapticFeedback.prepare()
tapticFeedback.impactOccurred()
case "medium":
let tapticFeedback = UIImpactFeedbackGenerator(style: .medium)
tapticFeedback.prepare()
tapticFeedback.impactOccurred()
case "light":
let tapticFeedback = UIImpactFeedbackGenerator(style: .light)
tapticFeedback.prepare()
tapticFeedback.impactOccurred()
default:
let tapticFeedback = UIImpactFeedbackGenerator(style: .medium)
tapticFeedback.prepare()
tapticFeedback.impactOccurred()
}
}
func compassTapticFeedback(_ angle: CGFloat) {
switch Int(angle) {
case 0:
tapticFeedback("heavy")
case 30:
tapticFeedback("heavy")
case 60:
tapticFeedback("heavy")
case 90:
tapticFeedback("heavy")
case 120:
tapticFeedback("heavy")
case 250:
tapticFeedback("heavy")
case 180:
tapticFeedback("heavy")
case 210:
tapticFeedback("heavy")
case 240:
tapticFeedback("heavy")
case 270:
tapticFeedback("heavy")
case 300:
tapticFeedback("heavy")
case 330:
tapticFeedback("heavy")
default:
return
}
}
可能是因为我对角度做了很多计算以获得没有零分数的值? 我不知道。 即使我不确定这是原因。
问题是您正在检查当前角度是否是30
的倍数。 这样做的问题是,如果您将设备旋转得太快,该数字将被跳过,因此不会被检测到。
在完成compassTapticFeedback(_:)
的缩短版本后,如下面的进一步提示中的第二点所示,我添加了更多代码以使该方法检测中间跳过的角度:
enum TapticSync {
static var lastAngle: CGFloat = 0
}
func compassTapticFeedback(_ angle: CGFloat) {
// If the angle is 30°, carry on. Otherwise do more checks
if !Int(angle).isMultiple(of: 30) {
// If there was an angle at a multiple of 30° skipped, carry on. Otherwise do not trigger haptic feedback.
let minVal = min(angle, TapticSync.lastAngle)
let maxVal = max(angle, TapticSync.lastAngle)
let roundUpToNextMultiple = ceil(minVal / 30) * 30
guard maxVal > roundUpToNextMultiple else { return }
}
// If the checks were passed, trigger the haptic feedback and update the last angle
tapticFeedback("heavy")
TapticSync.lastAngle = angle
}
.prepare()
在您的情况下, tapticFeedback.prepare()
毫无意义。 正如.prepare()
的文档中.prepare()
:
调用 prepare() 然后立即触发反馈(中间没有任何时间)不会改善延迟。
你应该:
想想什么时候可以最好地准备发电机。 在触发反馈的事件之前调用 prepare()。 系统需要时间来准备 Taptic Engine 以实现最小延迟。
有关完整信息,请参阅文档。
在您的情况下,您不需要switch
来检查每个 30 的倍数的角度。相反,将compassTapticFeedback(_:)
更改为如下所示:
func compassTapticFeedback(_ angle: CGFloat) {
if Int(angle).isMultiple(of: 30) {
tapticFeedback("heavy")
}
}
由于这些部分,以度为单位的方向是相反的(删除了不必要的self.
):
-location.currentHeading + 360
compassTapticFeedback(-heading + 360)
相反,因此度数顺时针增加,请使用:
location.currentHeading
compassTapticFeedback(heading)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.