Use detailCalloutAccessoryView as third Annotation property - swift

I am a newbie at Swift as well as Stackoverflow, and I was wondering if there is a way to import data from my plist to detailCalloutAccesoryView in the same manner as I import to "title" and "subtitle" in my map annotation callouts? This way, I could avoid having to make my own custom map annotation, and rather use the built-in features of MapKit.
I am calling my variables to title and subtitle like this:
var myData: NSArray?
if let path = NSBundle.mainBundle().pathForResource("myData", ofType: "plist") {
myData = NSArray(contentsOfFile: path)
}
if let items = myData {
for item in items {
let lat = item.valueForKey("Latitude") as! Double
let long = item.valueForKey("Longitude") as! Double
let myAnnotation = Mydata(value1: "Value1", value2: "Value2", value3: "Value3", latitude: lat, longitude: long)
// Define "Value1 to be shown as title in Callout
myAnnotation = item.valueForKey("Value1") as? String
// Define "Value2 to be shown as subtitle in Callout
myAnnotation.subtitle = item.valueForKey("Value2") as? String
annotations.append(myAnnotation)
}
}
return annotations
}
By now, I am just showing the same value in all annotations for detailCalloutAccessoryView in the place of subtitle using the following piece code:
let detailAccessory = UILabel(frame: CGRectMake(0,0,50,30))
detailAccessory.text = "Value3" // Obviously, shows constant value for all annotations
detailAccessory.font = UIFont(name: "Verdana", size: 10)
pinView?.detailCalloutAccessoryView = detailAccessory
Please, do not let my ignorance annoy you...

You will need to implement func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? delegate method. In there you can customize detailCalloutAccessoryView.
For detailed explanation refer to https://developer.apple.com/videos/play/wwdc2015/206/

Related

Annotations showing wrong image

Is there any way that annotations might show other images then it should supose ? Is it a way to fix that ?
I've got a werid problem. After my clusters going to evolve to the single annotations then after updating ( zoom out - zoom in ) they images going to be diferent then it should be. After debuging it says that the color of the pin view image is the one which I suposed. Where I could hook up yet to see the exact data ? Maybe something after viewFor which get invoked.
Here is a logic how am I doing this.
The dictionary to knows witch model is on the top of the added annotations.
var dicAnnotations = [FBAnnotation : MyModel]()
Through the loop of [MyModel] i am appending data to the array of the [FBAnnotation] which is needed for saving them via FBClusteringManager. Then in the same time while the new annotation is added to the [FBAnnotation] I am adding
self.dicAnnotations[fbAnnotation] = objModel
to know which annotation have which object.
So as we know how I am soring the data of annotations, how Am I indexing them, lets have a look on the delegate of the MKMapView.
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
DispatchQueue.global(qos: .userInitiated).async {
let mapBoundsWidth = Double(self.mapView.bounds.size.width)
let mapRectWidth = self.mapView.visibleMapRect.size.width
let scale = mapBoundsWidth / mapRectWidth
let annotationArray = self.clusterManager.clusteredAnnotations(withinMapRect: self.mapView.visibleMapRect, zoomScale:scale)
for ann in annotationArray {
if ann is FBAnnotation {
let a = ann as! FBAnnotation
print("Here u are , my color is : \(self.dicAnnotations[a]!.lineColor)")
}
}
DispatchQueue.main.async {
self.clusterManager.display(annotations: annotationArray, onMapView: self.mapView)
}
}
}
The for loop is for checking if the annotation is the one which should be - and it is!
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var reuseId = ""
if annotation is FBAnnotationCluster {
reuseId = "Cluster"
var clusterView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if clusterView == nil {
clusterView = FBAnnotationClusterView(annotation: annotation, reuseIdentifier: reuseId, configuration: FBAnnotationClusterViewConfiguration.default())
} else {
clusterView?.annotation = annotation
}
return clusterView
}
else {
let ann = annotation as! FBAnnotation
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: "Pin")
pinView = MKAnnotationView(annotation: ann, reuseIdentifier: "Pin")
var modelType = dicAnnotations[ann]?.modelType
modelType = modelType?.modelTypeToString(modelType: modelType!)
let modelColor = dicAnnotations[ann]?.lineColor
let modelDirection = dicAnnotations[ann]?.withHeading360
print("\(modelType!)_\(modelColor!)")
pinView?.image = UIImage(named: "\(modelType!)_\(modelColor!)")?.rotated(by: Measurement(value: modelDirection!, unit: .degrees))
return pinView
}
}
How it looks in the stack call which I am able get :
Here u are , my color is : yellow
(lldb) po dicAnnotations[ann]
▿ Optional<MyModel>
▿ some : <Project.MyModel: 0x101b656f0>
(lldb) po dicAnnotations[ann]?.lineColor
▿ Optional<String>
- some : "yellow"
From :
// viewFor
... else { pinView?.annotation = ann } ...
Any ideas ? It shows me would say "random colored image".
Thanks in advance!
Solution
I've edited the delegate viewFor. Deleted the if pinView == null condition and else as well. Somehow it was not working like it suposed to.

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!)

Assigning an accessibility identifier to an MKMapView object

I'm trying to configure snapshot for an app I'm working in, it already works in the english version but in the localized versions I don't know how to assign an accessibility identifier to a pin in the Map in MKMapView, somebody knows hows to do this?
Thanks.
Accessibility identifiers are a great way to separate your application's language from Xcode UI Testing. The identifier comes from UIAccessibilityIdentification which UIView already conforms to. However, neither NSObject nor MKAnnotation conform to the protocol. So you have to set that conformance yourself.
class Annotation: NSObject, MKAnnotation, UIAccessibilityIdentification {
let coordinate: CLLocationCoordinate2D
let title: String?
var accessibilityIdentifier: String?
init(title: String?, coordinate: CLLocationCoordinate2D) {
self.title = title
self.coordinate = coordinate
}
}
let coordinate = CLLocationCoordinate2DMake(40.703490, -73.987770)
let annotation = Annotation(title: "BeerMenus HQ", coordinate: coordinate)
annotation.accessibilityIdentifier = "Custom Identifier"
let mapView = MKMapView()
mapView.addAnnotation(annotation)
Then under test you can reference the annotation via otherElements.
let app = XCUIApplication()
let annotation = app.maps.element.otherElements["Custom Identifier"]
annotation.tap()

How to customize multiple annotations? Parse-Swift

I have been struggling with this for days but I still can't find a way to do it. Basically I have this map view and I am getting the annotations data (location,title,subtitle) from Parse, all I want to do is to replace the default pins with a custom one, I managed to customize one when I only use one annotation but for multiple it is not working, this is what I have for adding the annotations:
func setAnnotations(){
//Run query and get objects from parse, then add annotations
var query = PFQuery(className: "Countries")
query.orderByDescending("Location")
query.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]?,error: NSError?)-> Void in
if error == nil{
let myObjects = objects as! [PFObject]
for object in myObjects{
//data for annotation
var annotation = MKPointAnnotation()
let place = object["Location"] as? PFGeoPoint
let placeName = object["nameEnglish"] as? String
annotation.title = placeName
annotation.subtitle = placeName
annotation.coordinate = CLLocationCoordinate2DMake(place!.latitude,place!.longitude)
//add annotations
self.mapView.addAnnotation(annotation)
}
}else{println(error)}
}
}
How would I apply the "dequeueReusableAnnotationViewWithIdentifier" here?
You will want to use the viewForAnnotation delegate method similar to this answer. Make sure you also implement the MKMapViewDelegate protocol and set your controller to be the delegate.
Other than that, all you need to do is update your query to create and add your custom annotations like you are right now.
Cheers,
Russell

viewForAnnotation not being called (using Alamofire to parse JSON)

I'm new to iOS programming. I prefer to use Swift.
What I'm trying to do is call a web service that returns some JSON, parse the JSON into a custom object called Entry and plot those entries on a map.
I am using AlamoFire to make the web service call and SwiftyJSON to parse the JSON into Entry objects like below
request(.GET, URLString: "https://myURLThatReturnsJson")
.responseJSON { (_, _, json, error) in
if let json: AnyObject = json{
let jsonEntries = JSON(json)
for result in jsonEntries["entries"].arrayValue {
let business_name = result["business_name"].stringValue
let latitude = result["lat"].stringValue
let longitude = result["lng"].stringValue
let category = result["category"].stringValue
let address = result["address"].stringValue
let city = result["city"].stringValue
let type = result["type"].stringValue
let location = result["location"].stringValue
let valid = result["valid"].stringValue
let comments = result["comments"].stringValue
let date = result["date"].stringValue
let username = result["username"].stringValue
let additional_comment_count = result["additional_comment_count"].stringValue
let entry : Entry = Entry(
business_name: business_name,
latitude: latitude,
longitude: longitude,
category: category,
address: address,
city: city,
type: type,
location: location,
valid: valid,
comments: comments,
date: date,
username: username,
additional_comment_count: additional_comment_count,
title: business_name,
subtitle: location,
coordinate: CLLocationCoordinate2D(latitude: (latitude as NSString).doubleValue, longitude: (longitude as NSString).doubleValue))
entries.append(entry)
}
// Now we have our array of entries. Now plot them.
for entry in entries{
self.mapView.addAnnotation(entry)
}
}
}
So as you can see in the code above I am also mapping the entries within the AlamoFire request (don't know if this is bad because AlamoFire is done on a separate thread I believe).
I also have a viewForAnnotations method that looks like below
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
print("viewForAnnotation called")
return nil
}
My viewForAnnotation method is not being called at all (break point on print line is not being hit).
Any help is appreciated!
Please make sure to set the delegate property of mapview to self.
mapview.delegate = self
You can also do this by connecting the delegate outlet of mapview to ViewController using Connection Inspector (Interface Builder)