First in your view you want to request the HeadingProvider to start out updating heading. It’s worthwhile to hearken to objectWillChange notification, the closure has one argument which is the brand new worth that’s being set on ObservableObject.
I’ve modified your Compass a bit:
struct Compass: View {
@StateObject var headingProvider = HeadingProvider()
@State non-public var angle: CGFloat = 0
var physique: some View {
VStack {
Picture("arrow")
.resizable()
.aspectRatio(contentMode: .match)
.body(width: 300, top: 300)
.modifier(RotationEffect(angle: angle))
.onReceive(self.headingProvider.objectWillChange) { newHeading in
withAnimation(.easeInOut(period: 1.0)) {
self.angle = newHeading
}
}
Textual content(String("(angle)"))
.font(.system(dimension: 20))
.fontWeight(.mild)
.padding(.prime, 15)
} .onAppear(carry out: {
self.headingProvider.updateHeading()
})
}
}
I’ve written an instance HeadingProvider:
public class HeadingProvider: NSObject, ObservableObject {
public let objectWillChange = PassthroughSubject<CGFloat,By no means>()
public non-public(set) var heading: CGFloat = 0 {
willSet {
objectWillChange.ship(newValue)
}
}
non-public let locationManager: CLLocationManager
public override init(){
self.locationManager = CLLocationManager()
tremendous.init()
self.locationManager.delegate = self
}
public func updateHeading() {
locationManager.startUpdatingHeading()
}
}
extension HeadingProvider: CLLocationManagerDelegate {
public func locationManager(_ supervisor: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
DispatchQueue.important.async {
self.heading = CGFloat(newHeading.trueHeading)
}
}
}
Keep in mind you want to deal with asking for permission to learn consumer’s location and you want to name stopUpdatingHeading() sooner or later.