MapView crashes with setting to delegate - swift

I am setting my map view to delegate yet so I can place an annotation callout on my pin, but I have a geocode that does something else only when a button is clicked. When I set the map view to delegate and I try to place a pin it crashes. How can I fix this?
func action(gestureRecognizer:UIGestureRecognizer) {
let touchPoint = gestureRecognizer.locationInView(self.mapView)
let newCoord:CLLocationCoordinate2D = mapView.convertPoint(touchPoint, toCoordinateFromView: self.mapView)
//var newAnotation = MKPointAnnotation()
//
self.mapView.delegate = self
//
self.newAnotation = MKPointAnnotation()
self.newAnotation.coordinate = newCoord
newAnotation.title = "New Location"
newAnotation.subtitle = "New Subtitle"
//mapView.addAnnotation(newAnotation)
self.pinAnnotationView = MKPinAnnotationView(annotation: self.newAnotation, reuseIdentifier: nil)
self.mapView.centerCoordinate = self.newAnotation.coordinate
self.mapView.addAnnotation(self.pinAnnotationView.annotation!)
}
Screenshot of where it crashes,

You must be getting the following error log in your console output.And thats because you have not initialise your geoCoder instance.
fatal error: unexpectedly found nil while unwrapping an Optional value
Declare it like this
var geoCoder: CLGeocoder = CLGeocoder()

Related

Swift error: Cannot assign to property: 'coordinate' is immutable

The problem is when I write this line of code on which I try to convert the user location to another coordinate, I get this error: Cannot assign to property: 'coordinate' is immutable
The code is:
var location = sender.location(in: self.mapView)
let locCoord = self.mapView.convert(location, toCoordinateFrom: self.mapView)
self.mapView.userLocation.coordinate = locCoord *// Cannot assign to property:'coordinate' is immutable*
Can you help please?
As the error says the coordibate property is immutable
var coordinate: CLLocationCoordinate2D { get }
var userLocation: CLLocation { get }
you can't alter it in addition to userLocation , if you need a different location go directly with
If your want to assign new value then use var instead of let , let is used to non changed values

Swift MapKit Annotation using coordinate from API not showing up on map

I used coordinate from API to put an annotation on map, but it didn't show up while:
I declared a new coordinate which is not from API, can show up on map.
I can print the coordinate form API, and the coordinate was fine.
I put mapView.addAnnotation() in DispatchQueue.main.async.
Can anyone tell me how to fix it? Thanks!
Here is my code:
extension LocationViewController: ParkProviderDelegate {
func didFetch(by provider: ParkProvider) {
DispatchQueue.main.async {
let annotation = MKPointAnnotation()
let coordinate = self.provider.parks[0].coordinate
self.mapView?.addAnnotation(annotation)
}
}
Try the following code:
DispatchQueue.main.async {
let annotation = MKPointAnnotation()
let coordinate = self.provider.parks[0].coordinate
annotation.coordinate = coordinate
annotation.title = "title"
annotation.subtitle = "subtitle"
self.mapView?.addAnnotation(annotation)
}

How do I add a custom annotation to a map view with images in Swift 2?

I have created an MKMapView, but I need to add multiple annotations with images in Swift 2, how would I do this?
First you have to create a MKAnnotationView, use this function to create your marker :
internal func setupMarker(image:UIImage,long:Double,lat:Double,title:String,subtitle:String) -> MKAnnotationView{
var pinAnnotationView:MKAnnotationView!
var pointAnnotation:MKPointAnnotation!
pointAnnotation = MKPointAnnotation()
pointAnnotation.title = title
pointAnnotation.subtitle = subtitle
pointAnnotation.coordinate = CLLocationCoordinate2D(latitude:lat, longitude:long)
pinAnnotationView = MKPinAnnotationView(annotation: pointAnnotation, reuseIdentifier: nil)
pinAnnotationView.image = image
pinAnnotationView.canShowCallout = true
return pinAnnotationView
}
Create your marker:
var marker = setupMarker(store.image.image, long: store.location.longitude, lat: store.location.latitude, param: "store",storeId: store.description))
Add the marker to your MapView
mapView.addAnnotation(marker.annotation!)

set the callout annotation title from "DidSelectAnnotationView" in Swift 2.0 and Data From CoreData

please help. =) i have a problem to set the callout title. I receive the informations from core data with predicates.
When i click on a annotation on the map, i receive all data from the pin in my Logs.
how can set the title in the callout Bubble?
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView:MKPinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "CheckpointPins")
if annotation is MKUserLocation {
return nil }
else {
let pred:NSPredicate = NSPredicate(format: "checkpoint_longitude != nil && checkpoint_latitude != nil")
let items = fetchedResultsController?.fetchedObjects
let filt = (items! as NSArray).filteredArrayUsingPredicate(pred)
let startCheckPoint:Checkpoint = (filt as NSArray).firstObject as! Checkpoint!
let endCheckpoint:Checkpoint = (filt as NSArray).lastObject as! Checkpoint!
if filt.count != 0 {
if startCheckPoint .isEqual(annotation) {
annotationView.pinTintColor = MKPinAnnotationView.greenPinColor()
}else if endCheckpoint.isEqual(annotation) {
annotationView.pinTintColor = MKPinAnnotationView.purplePinColor()
}else {
annotationView.pinTintColor = MKPinAnnotationView.redPinColor()
}
}
let point = annotation as! Checkpoint
annotationView.tag = (point.checkpoint_order?.integerValue)!
annotationView.enabled = true
annotationView.animatesDrop = true
// annotationView.canShowCallout = true
annotationView.annotation = annotation
// annotationView.opaque = false
print("tag = \(annotationView.tag)")
}
return annotationView
}
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
if !(view.annotation!.isKindOfClass(MKUserLocation)) {
let pred:NSPredicate = NSPredicate(format: "checkpoint_longitude != nil && checkpoint_latitude != nil")
let pred2:NSPredicate = NSPredicate(format: "checkpoint_order == %d", view.tag)
let compoundPredicate:NSPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [pred, pred2])
let items = fetchedResultsController?.fetchedObjects
let filt = (items! as NSArray).filteredArrayUsingPredicate(compoundPredicate)
let point:Checkpoint = (filt as NSArray).firstObject as! Checkpoint
print(point.description)
}
}
}
First of all, if you want to show callouts, you need to set canShowCallout to true. There are no callouts unless you enable them.
In a comment you said that you're getting a crash with an error that reads must implement title when canShowCallout is YES on corresponding view <MKPinAnnotationView: 0x7fb9ef536e70... What this is telling you is that the object you used as your annotation does not implement the title part of the MKAnnotation protocol. The title is an optional part of the protocol unless you use callouts in which case you must implement it. The title is what's displayed on the callout. The error message is telling you that you enabled the callout but didn't provide a title to display. You can either add title to the class you're using as the MKAnnotation or you can skip using callouts.

mapView:didAddAnnotationViews doesn't always pick up the annotations

I have placed a number of annotations on a map, and when the user touches the location button, the view zooms in on the user location, which contains a number of annotations.
mapView:didAddAnnotationViews is called and should add all the annotations inside the current view into an NSArray.
Sometimes it adds all the annotations without any problems, but other times, it only adds the one annotation which is the user location (blue dot).
I suspect it may have to do with being called before the map has finished rendering, but i'm not sure.
Not sure if it's possible to link the function mapViewDidFinishRenderingMap to didAddAnnotationViews so that it will only load once the view has been completed loading (including all the annotations).
Would appreciate any advice regarding this, as I am relatively new to Swift.
Here's some of my code. I've got a timer that runs every second and prints out the size of the array in the console.
var timer = NSTimer()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update", userInfo: nil, repeats: true)
func mapView (mapView: MKMapView!, didAddAnnotationViews views: [AnyObject]!) {
pinannotationarray = views
}
func update() {
if (pinannotationarray != nil && locationManager.location != nil)
{
println("pinannotationarray size \(pinannotationarray.count)")
}
}
** Revised Code **
var annSet: AnyObject!
func mapView(mapView: MKMapView!, regionDidChangeAnimated animated: Bool) {
annSet = mapView.annotationsInMapRect(mapView.visibleMapRect)
println("regionDidChangeAnimate: annSet count = \(annSet.count)")
for (var i = 0; i < annSet.count; i++)
{
pinannotation = annSet.allObjects[i].annotation as? MyAnnotation
//fatal error: unexpectedly found nil while unwrapping an Optional value
println(pinannotation.title)
}
}
The annotationsInMapRect method returns an NSSet containing the annotation model objects (eg. MKPointAnnotation) -- not the views (eg. MKAnnotationView).
That also means annSet.allObjects will be an NSArray containing the annotation model objects.
That means annSet.allObjects[i].annotation is invalid and will fail (annotation views have an annotation property and not the annotations themselves) which leaves pinannotation as nil resulting in the crash.
Change the assignment to:
pinannotation = annSet.allObjects[i] as? MyAnnotation
println(pinannotation.title)
or to be a little safer:
if let pa = annSet.allObjects[i] as? MyAnnotation {
println(pa.title)
}
By the way, you don't even need to generate an NSArray from the NSSet. You can iterate the NSSet directly:
for ann in annSet as NSSet {
if let ma = ann as? MyAnnotation {
println("ma.title = \(ma.title)")
}
}