1

I am implementing Local Search in my CoreLocation and MapKit frimeworks based app. I am following this Tutorial

I am getting error below error :

Cannot convert value of type '(MKLocalSearchResponse!, NSError!) -> ()' to expected argument type 'MKLocalSearchCompletionHandler' (aka '(Optional, Optional) -> ()')

Here is my code:

import UIKit
import CoreLocation
import MapKit


class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate{
    private let LocationManager = CLLocationManager()
    let request = MKLocalSearchRequest()
    private var previousPoint:CLLocation?
    private var totalMovementDistance:CLLocationDistance = 0




    @IBOutlet var mapView: MKMapView!


    @IBOutlet var searchText: UITextField!
    var matchingItems: [MKMapItem] = [MKMapItem]()

    @IBAction func textFieldReturn(sender:AnyObject) {
        sender.resignFirstResponder()
        mapView.removeAnnotations(mapView.annotations)
        self.performSearch()

    }

    @IBOutlet var latitudeLabel: UILabel!
    @IBOutlet var longitudeLabel: UILabel!
    @IBOutlet var horizontalAccuracy: UILabel!
    @IBOutlet var altitudeLabel: UILabel!
    @IBOutlet var verticalAccuracyLabel: UILabel!
    @IBOutlet var distanceTraveledLabel: UILabel!






    override func viewDidLoad() {
        super.viewDidLoad()
        LocationManager.delegate = self
        LocationManager.desiredAccuracy = kCLLocationAccuracyBest
        LocationManager.requestWhenInUseAuthorization()



        // Do any additional setup after loading the view, typically from a nib.
    }



    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        print("Authorization Status Changed to \(status.rawValue)")
        switch status {
        case .Authorized, .AuthorizedWhenInUse:
            LocationManager.startUpdatingLocation()
            mapView.showsUserLocation = true

        default:
            LocationManager.stopUpdatingLocation()
            mapView.showsUserLocation = false
        }
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        let errorType = error.code == CLError.Denied.rawValue ? "Access Denied": "Error \(error.code)"
        let alertController = UIAlertController(title: "Location Manager Error", message: errorType, preferredStyle: .Alert)
        let okAction = UIAlertAction(title: "OK", style: .Cancel, handler: {action in})
        alertController.addAction(okAction)
        presentViewController(alertController, animated: true, completion: nil)
    }

    func performSearch() {

        matchingItems.removeAll()
        let request = MKLocalSearchRequest()
        request.naturalLanguageQuery = searchText.text
        request.region = mapView.region

        let search = MKLocalSearch(request: request)

        search.startWithCompletionHandler { (localResponse:MKLocalSearchResponse?, error: NSError?) -> Void in


            if error != nil {
                print("Error occured in search: \(error?.localizedDescription)")
            } else if localResponse == 0 {
                print("No matches found")
            } else {
                print("Matches found")

                for item in localResponse.mapItems  {
                    print("Name = \(item.name)")
                    print("Phone = \(item.phoneNumber)")

                    self.matchingItems.append(item as MKMapItem)
                    print("Matching items = \(self.matchingItems.count)")

                    var annotation = MKPointAnnotation()
                    annotation.coordinate = item.placemark.coordinate
                    annotation.title = item.name
                    self.mapView.addAnnotation(annotation)
                }
            }
        }
    }


    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let newLocation = (locations as [CLLocation]) [locations.count - 1]

        let latitudeString = String(format: "%g\u{00B0}", newLocation.coordinate.latitude)
        latitudeLabel.text = latitudeString

        let longitudeString = String(format: "%g\u{00B0}", newLocation.coordinate.longitude)
        longitudeLabel.text = longitudeString

        let horizontalAccuracyString = String(format: "%gm", newLocation.horizontalAccuracy)
        horizontalAccuracy.text = horizontalAccuracyString

        let altitudeString = String(format: "%gm", newLocation.altitude)
        altitudeLabel.text = altitudeString

        let verticalAccuracyString = String(format: "%gm", newLocation.verticalAccuracy)
        verticalAccuracyLabel.text = verticalAccuracyString

        if newLocation.horizontalAccuracy < 0 {
            //invalid accuracy
            return

        }


        if newLocation.horizontalAccuracy > 100 ||
            newLocation.verticalAccuracy > 50 {
                return
        }

        if previousPoint == nil {
            totalMovementDistance = 0
            let start = Place(title:"Strating Point", subtitle:"This is where we started", coordinate:newLocation.coordinate)
            mapView.addAnnotation(start)
            let region = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 100, 100)
            mapView.setRegion(region, animated:true)


        }else {
            print("movement distance: \(newLocation.distanceFromLocation(previousPoint!))")
            totalMovementDistance += newLocation.distanceFromLocation(previousPoint!)

        }

        previousPoint = newLocation

        let distanceString = String(format: "%gm", totalMovementDistance)
        distanceTraveledLabel.text = distanceString



    }



}

Error is on this line:

search.startWithCompletionHandler({(response:
            MKLocalSearchResponse!,

Edited:

enter image description here

1
  • The error that you're receiving is because this variables are of type optional, for access then you need to use ?.. something like: error?.localizedDescription or first unwrap the values if let error = error{ // your code} Commented Jun 30, 2016 at 20:32

3 Answers 3

2

Replace the ! in the arguments with ? (because that's the signature of the method) Example:

    search.startWithCompletionHandler { (localResponse:MKLocalSearchResponse?, error:NSError?) -> Void in

    }
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for answer and comment It helped to remove error.
1

The error message simply says that the signature of the method is wrong, because it expects optional types.

Confirm it by pressing ⇧⌘0 and typing MKLocalSearchCompletionHandler and you will see

typealias MKLocalSearchCompletionHandler = (MKLocalSearchResponse?, NSError?) -> Void

So, it's

search.startWithCompletionHandler({(response:
        MKLocalSearchResponse?,
        error: NSError?) in ...

but you can – and should – omit the type annotations

search.startWithCompletionHandler({(response, error) in ...

3 Comments

Thank you, I have updated my code as you suggested Now I get 3 more error I am not getting how to overcome with that. sorry I am complete beginner in this.
localResponse is not the same as response. Check the consistency of your parameter names
Yes, you used the code from the answer of José, but he wrote localResponse rather than your original parameter name response which breaks your code.
1

Try this:

func performSearch() {

    var matchingItems = [MKMapItem]()
    let mapView = MKMapView(frame: CGRectMake(0,0,300,300))

    let request = MKLocalSearchRequest()
    request.naturalLanguageQuery = "Restaurants 30518"
    request.region = mapView.region

    let search = MKLocalSearch(request: request)

    search.startWithCompletionHandler { (response, error) in

        if let error = error  {
            print("Error occured in search: \(error.localizedDescription)")
        } else if let response = response {
            print("Got response")
            if response.mapItems.count == 0 {
                print("No matches found")
            } else {
                print("Matches found")

                for item in response.mapItems as [MKMapItem] {
                    print("Name = \(item.name)")
                    print("Phone = \(item.phoneNumber)")

                    matchingItems.append(item as MKMapItem)
                    print("Matching items = \(matchingItems.count)")

                    let annotation = MKPointAnnotation()
                    annotation.coordinate = item.placemark.coordinate
                    annotation.title = item.name
                    mapView.addAnnotation(annotation)
                }
            }
        }
    }
}

The response and error are optionals, don't force unwrap them.

2 Comments

The forced unwrapping is no problem in this case. If an error occurs, error is definitely not nil, and if there is no error, response is definitely not nil.
@vadian I meant in the method signature. (response: MKLocalSearchResponse!, error: NSError!) is wrong, He should leave them as optionals in the method signature and unwrap them inside (could be forced I guess but not at the level where it was done in the question).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.