I am having some trouble getting a custom annotation to load inside of my map view when I try to place a pin.
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate{
@IBAction func ReportBtn(sender: AnyObject) {
//MARK: Report Date And Time Details
let ReportTime = NSDate()
let TimeStamp = NSDateFormatter()
TimeStamp.timeStyle = NSDateFormatterStyle.ShortStyle
TimeStamp.dateStyle = NSDateFormatterStyle.ShortStyle
TimeStamp.stringFromDate(ReportTime)
//MARK: Default Point Annotation Begins
let ReportAnnotation = MKPointAnnotation()
ReportAnnotation.title = "Annotation Created"
ReportAnnotation.subtitle = ReportTime.description
ReportAnnotation.coordinate = locationManager.location!.coordinate
mapView(MainMap, viewForAnnotation: ReportAnnotation)
MainMap.addAnnotation(ReportAnnotation)
}
@IBOutlet weak var MainMap: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.startUpdatingLocation()
self.MainMap.showsUserLocation = true
}
//MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02 ))
self.MainMap.setRegion(region, animated: true)
//self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError){
print(error.localizedDescription)
}
//MARK:Custom Annotation Begins Here
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
guard !annotation.isKindOfClass(MKUserLocation) else {
return nil
}
/*if annotation.isKindOfClass(MKUserLocation){
//emty return, guard wasn't cooperating
}else{
return nil
}*/
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier){
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else{
let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
av.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
annotationView = av
}
if let annotationView = annotationView {
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "image.png")
}
return annotationView
}
}
Added Information
I am positive that the button functionality works perfect. With the current code, dumped above, the default red pin annotation appears right where it should. When I tap on the pin, the description I specified also appears without an issue. The only problem I am having with this code is that I cannot get my image to take the place of the boring, default red pin
From the code and according to the MapKit guide, your code look correct. I am thinking that it could be this line
annotationView.image = UIImage(named: "image.png")
Is there a chance that
image.png
could be the wrong image name or not added in to the project when compile? Also just fyi, if you are using.xcassets
, you does not have to add a.png
.As
annotationView.image
is a optional, when the imageUIImage(named: "image.png")
is nil, it will not crash but just render the default pin image.If this is not the issue, please provide more info on the debugging steps that you have taken so the rest of us can understand better and help you. Cheers =)
I recommend subclassing `MKPointAnnotation.
Pokémon Pin
I have included only the necessary code to display a custom map pin. Think of it as a template.
Outline
We will create a point annotation object and assigning a custom image name with the
CustomPointAnnotation
class.We will subclass the
MKPointAnnotation
to set image and assign it on the delegate protocol methodviewForAnnotation
.We will add an annotation view to the map after setting the coordinate of the point annotation with a title and a subtitle.
We will implement the
viewForAnnotation
method which is anMKMapViewDelegate
protocol method which gets called for pins to display on the map.viewForAnnotation
protocol method is the best place to customise the pin view and assign a custom image to it.We will dequeue and return a reusable annotation for the given identifier and cast the annotation to our custom
CustomPointAnnotation
class in order to access the image name of the pin.We will create a new image set in
Assets.xcassets
and place image@3x.png and image@2x.png accordingly.Don't forget plist.
NSLocationAlwaysUsageDescription
andNSLocationWhenInUseUsageDescription
As always test on a real device.
The swizzle
There are a few issues you need to deal with.
MKMapView and annotations
Firstly, it is necessary to understand how
MKMapView
displays an annotation view from an annotation. There areAn
MKAnnotation
holds the data for a location on the map. You create this data and hand it toMKMapView
. At some point in the future, when the map view is ready to display the annotation it will call back to the delegate and ask it to create anMKAnnotationView
for anMKAnnotation
. The delegate creates and returns the view and the map view displays it. You specify the delegate in the storyboard, or in code e.g.mapView.delegate = self
.Location
Tracking the users location is complicated by:
Your code needs to deal with authorisation by checking
CLLocationManager.authorizationStatus
, and implementingCLLocationManagerDelegate
methods.Note that to use
requestWhenInUseAuthorization
requires entry forNSLocationWhenInUseUsageDescription
inInfo.plist
Example
Example project on GitHub.
check your image.png in your project bundle or Assets.xcassets
Do as follow may be work for you.
1) Create custom class for the Annotation Pin.
2)Define variable as below.
3) Call below method in
viewDidLoad()
4) Put below code in
viewWillAppear()
5) Most important implement below method.
6) Execute below code where you you have received custom pin image