iosswiftmapkitmkpolyline

MKPolyline isn't drawing on the map. How can I resolve this issue?


I am trying to draw an MKPolyline on a map. When I do a simulated run on the app, the location moves correctly but no line is drawn. How can I resolve this issue?

    mapView.delegate = self
    mapView.showsUserLocation = true
    mapView.mapType = MKMapType(rawValue: 0)!
    mapView.userTrackingMode = MKUserTrackingMode(rawValue: 2)!
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
    mapView.mapType = MKMapType(rawValue: 0)!
}

override func viewWillAppear(_ animated: Bool) {
    locationManager.startUpdatingHeading()
    locationManager.startUpdatingLocation()
}

override func viewWillDisappear(_ animated: Bool) {
    locationManager.stopUpdatingHeading()
    locationManager.stopUpdatingLocation()
}

// MARK: - CLLocationManager delegate

func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
    //drawing path or route covered
    if let oldLocationNew = oldLocation as CLLocation?{
        let oldCoordinates = oldLocationNew.coordinate
        let newCoordinates = newLocation.coordinate
        var area = [oldCoordinates, newCoordinates]
        var polyline = MKPolyline(coordinates: &area, count: area.count)
        mapView.add(polyline)
    }

    //calculation for location selection for pointing annoation
    if let previousLocationNew = previousLocation as CLLocation?{
        //case if previous location exists
        if previousLocation.distance(from: newLocation) > 200 {
            addAnnotationsOnMap(locationToPoint: newLocation)
            previousLocation = newLocation
        }
    }
    else{
        //case if previous location doesn't exists
        addAnnotationsOnMap(locationToPoint: newLocation)
        previousLocation = newLocation
    }
}

// MARK: - MKMapView delegate

func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {

    if (overlay is MKPolyline) {
        var pr = MKPolylineRenderer(overlay: overlay)
        pr.strokeColor = UIColor.red
        pr.lineWidth = 5
        return pr
    }

    return nil
}


func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if startDate == nil {
        startDate = Date()
    } else {
        print("elapsedTime:", String(format: "%.0fs", Date().timeIntervalSince(startDate)))
        timeLabel.text="\(Date().timeIntervalSince(startDate))"
    }
    if startLocation == nil {
        startLocation = locations.first
    } else if let location = locations.last {
        traveledDistance += lastLocation.distance(from: location)
        print("Traveled Distance:",  traveledDistance)
        distanceLabel.text="\(traveledDistance)"
        print("Straight Distance:", startLocation.distance(from: locations.last!))
    }
    lastLocation = locations.last
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    if (error as? CLError)?.code == .denied {
        manager.stopUpdatingLocation()
        manager.stopMonitoringSignificantLocationChanges()
    }
}

MKPolyline should be drawn as the user moves.


Solution

  • The signature for mapView(_:rendererFor:) is incorrect. It has changed. It is now:

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        switch overlay {
        case let polyline as MKPolyline:
            let renderer = MKPolylineRenderer(polyline: polyline)
            renderer.strokeColor = .red
            renderer.lineWidth = 5
            return renderer
    
        // you can add more `case`s for other overlay types as needed
    
        default:
            fatalError("Unexpected MKOverlay type")
        }
    }
    

    If you add a print statement or breakpoint inside your current method, I believe you will find that it’s not being called. And, of course, make sure that you’ve set the delegate of your map view, either in IB or programmatically.


    By the way, the old locationManager(_:didUpdateTo:from:) is deprecated. Use locationManager(_:didUpdateLocations:) instead. You’ll have to maintain your own reference to the savedLocation and the savedPolyline:

    var savedLocation: CLLocation?
    var savedPolyline: MKPolyline?
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last(where: { $0.horizontalAccuracy >= 0 }) else { return }
    
        var polyline: MKPolyline?
    
        if let oldCoordinate = savedLocation?.coordinate {
            let coordinates = [oldCoordinate, location.coordinate]
            polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
            mapView.addOverlay(polyline!)
        }
    
        // if you want to remove the old one
        // 
        // if let savedPolyline = savedPolyline {
        //     mapView.removeOverlay(savedPolyline)
        // }
        // 
        // savedPolyline = polyline
    
        savedLocation = location
    
        // ...
    }