MapKit: "Delegate must respond to locationManager:didUpdateLocations:"

Hi, I've been trying to develop an app that allows a user to drop a pin on the map once they've long pressed on it.

When trying to launch the app it throws a "Thread 1: "Delegate must respond to locationManager:didUpdateLocations:" error.

I would appreciate if you could help me locate the source of the issue and suggest a fix.

This is my first app and I am still not entirely sure what I am doing most of the time. ;)

Here's the code:
Code Block //
//  ViewController.swift
//  GetUserLocation
//
//  Created by Jakub Rakowski on 22/03/2021.
//
import UIKit
import MapKit
class ViewController: UIViewController , CLLocationManagerDelegate {
    @IBOutlet weak var MyMapView: MKMapView!
    let LocationManager = CLLocationManager ()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        LocationManager.delegate = self
        LocationManager.desiredAccuracy = kCLLocationAccuracyBest
        if(CLLocationManager.locationServicesEnabled()) {
            LocationManager.requestLocation()
            LocationManager.startUpdatingLocation()
        }
    }
//User Location
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation], didFailWithError error: Error) {
        if let UserLocation = locations.first {
            manager.stopUpdatingLocation()
            let userCoordinates = CLLocationCoordinate2D(latitude: LocationManager.location?.coordinate.latitude ?? 0.0, longitude: LocationManager.location?.coordinate.longitude ?? 0.0)
            let Span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
            let Region = MKCoordinateRegion(center: userCoordinates, span: Span)
            MyMapView.setRegion(Region, animated: true)
//Requesting Location Authorization
                func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
                    switch manager.authorizationStatus {
                    case .authorizedAlways:
                        return
                    case .authorizedWhenInUse:
                        return
                    case .denied:
                        return
                    case .restricted:
                        LocationManager.requestWhenInUseAuthorization()
                    case .notDetermined:
                        LocationManager.requestWhenInUseAuthorization()
                    default:
                        LocationManager.requestWhenInUseAuthorization()
                    }
                }
                func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
                    print(error)}
   
//User Location Pin
            let MyPin = MKPointAnnotation()
            MyPin.coordinate = userCoordinates
            MyPin.title = "Pin"
            MyPin.subtitle = "Subtitle"
            MyMapView.addAnnotation(MyPin)
        }}
            
//User Generated Pin
    @objc func addUserAnnotation(press:UILongPressGestureRecognizer){
                if press.state == .began
                {
                    let location = press.location(in: self.MyMapView)
                    let coordinates = MyMapView.convert(location, toCoordinateFrom: MyMapView)
      
                    let annotation = MKPointAnnotation()
                    annotation.coordinate = coordinates
  
                    annotation.title = "LongPress Annotation"
    
                    MyMapView.addAnnotation(annotation)
      
                    let uilpgr = UILongPressGestureRecognizer (target: self, action: #selector (addUserAnnotation(press:)))
           
                        uilpgr.minimumPressDuration = 1
                        MyMapView.addGestureRecognizer(uilpgr)
        
                        addUserAnnotation(press: uilpgr)
                    
                }
                
            }
    
}
                


Frankly saying, your code is broken in many ways and I do not see what you want to do with this code.
  • Your ViewController has 3 instance methods -- viewDidLoad(), locationManager(_:didUpdateLocations:didFailWithError:) and addUserAnnotation(press:)

But it does not have a method locationManager(_:didUpdateLocations:) which the error message is claiming.
  • Two methods are nested inside the method locationManager(_:didUpdateLocations:didFailWithError:), which seems to be a method CLLocationManagerDelegate, so they should not be nested.

You should bette care about proper indentation.
Keep using Select All(Cmd-A) and Re-Indent (Ctrl-I). You will find some of the func are indented deeper.


And this is not critical, but you are using Capitalized names such as MyMapView or LocationManager. That is making your code very, very, very hard to read.

Your ViewController should look like:
Code Block
import UIKit
import MapKit
class ViewController: UIViewController , CLLocationManagerDelegate {
@IBOutlet weak var myMapView: MKMapView!
let locationManager = CLLocationManager ()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.locationServicesEnabled() {
locationManager.requestLocation()
locationManager.startUpdatingLocation()
}
}
//User Location
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let userLocation = locations.first {
manager.stopUpdatingLocation()
let userCoordinates = CLLocationCoordinate2D(latitude: locationManager.location?.coordinate.latitude ?? 0.0, longitude: locationManager.location?.coordinate.longitude ?? 0.0)
let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
let region = MKCoordinateRegion(center: userCoordinates, span: span)
myMapView.setRegion(region, animated: true)
//User Location Pin
let myPin = MKPointAnnotation()
myPin.coordinate = userCoordinates
myPin.title = "Pin"
myPin.subtitle = "Subtitle"
myMapView.addAnnotation(myPin)
}
}
//Requesting Location Authorization
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .authorizedAlways:
return
case .authorizedWhenInUse:
return
case .denied:
return
case .restricted:
locationManager.requestWhenInUseAuthorization()
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
default:
locationManager.requestWhenInUseAuthorization()
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
//User Generated Pin
@objc func addUserAnnotation(press:UILongPressGestureRecognizer){
if press.state == .began {
let location = press.location(in: self.myMapView)
let coordinates = myMapView.convert(location, toCoordinateFrom: myMapView)
let annotation = MKPointAnnotation()
annotation.coordinate = coordinates
annotation.title = "LongPress Annotation"
myMapView.addAnnotation(annotation)
let uilpgr = UILongPressGestureRecognizer (target: self, action: #selector (addUserAnnotation(press:)))
uilpgr.minimumPressDuration = 1
myMapView.addGestureRecognizer(uilpgr)
addUserAnnotation(press: uilpgr)
}
}
}

  • You need to define the method locationManager(_:didUpdateLocations:), not locationManager(_:didUpdateLocations:didFailWithError:).

Are you using some sort of tutorials or textbooks? Do care about every single letter and symbol.

I haven't checked the content of each method, but at lease my code above will not cause Delegate must respond to locationManager:didUpdateLocations:.

Thanks! I'll give it another go. Perhaps I am using a bit too many tutorials at the same time and I don't quite know how to combine the elements properly. Thanks again.
MapKit: "Delegate must respond to locationManager:didUpdateLocations:"
 
 
Q