In fact, what you are doing wrong is to make the compass rotate in the didLocationChange method. In fact, you need to have a rotation in accordance with the True North of the Earth, and for this you need to use didUpdateLocationHeader . This gives you readings according to the true north of the earth. I am posting my code below. You can also find the complete working project on github
import UIKit import CoreLocation class ViewController: UIViewController ,CLLocationManagerDelegate{ @IBOutlet weak var ivCompassBack: UIImageView! @IBOutlet weak var ivCompassNeedle: UIImageView! let latOfKabah = 21.4225 let lngOfKabah = 39.8262 var location: CLLocation? let locationManager = CLLocationManager() var bearingOfKabah = Double() override func viewDidLoad() { super.viewDidLoad() initManager() } func initManager(){ locationManager.requestAlwaysAuthorization() locationManager.requestWhenInUseAuthorization() if CLLocationManager.locationServicesEnabled() { locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters locationManager.startUpdatingLocation() locationManager.startUpdatingHeading() } } func locationManager(_ manager: CLLocationManager, didUpdateHeading heading: CLHeading) { let north = -1 * heading.magneticHeading * Double.pi/180 let directionOfKabah = bearingOfKabah * Double.pi/180 + north ivCompassBack.transform = CGAffineTransform(rotationAngle: CGFloat(north)); ivCompassNeedle.transform = CGAffineTransform(rotationAngle: CGFloat(directionOfKabah)); } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { let newLocation = locations.last! location = newLocation bearingOfKabah = getBearingBetweenTwoPoints1(location!, latitudeOfKabah: self.latOfKabah, longitudeOfKabah: self.lngOfKabah)
source share