Select a map annotation from array programatically - ios

I've got an array of places. Each of these places are displayed on a MapView and on a TableView on the same screen. I'd like to pop up the pin annotation of a place when I tap the corresponding row on the table view.
I've got the following code to populate annotations:
for (int i = 0; i < [self.myPlaces count]; i++)
{
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
SPlaces *ev = [self.myPlaces objectAtIndex:i];
point.coordinate = CLLocationCoordinate2DMake([ev.location.latitude doubleValue], [ev.location.longitude doubleValue]);
point.title = ev.title;
point.subtitle = ev.type.name;
[self.myMap addAnnotation:point];
}
and this code to display an annotation when a row is selected on the TableView:
//row = tapped row on TableView
[self.myMap selectAnnotation:[[self.myMap annotations] objectAtIndex:row] animated:YES];
The issue is that the annotations seems to have a random index in the myMap annotations array.
I mean, i'd like to have this behavior:
users taps row 0 on Table view => annotation of pin 0 pops up on the map
users taps row 1 on Table view => annotation of pin 1 pops up on the map
users taps row 2 on Table view => annotation of pin 2 pops up on the map
But instead of this, I get:
users taps row 0 on Table view => annotation of pin 1 pops up on the map
users taps row 1 on Table view => annotation of pin 0 pops up on the map
users taps row 2 on Table view => annotation of pin 2 pops up on the map
...or any other random combination that change each time I restart the app.
Note that if I enable user's location, one of my pin annotation can have it's title randomly changed for "Current location".
I'm pretty sure I'm note populating or accessing the annotation correctly. Do you have any clue ?
Thanks !
EDIT: This post seems to say that you have to scan your annotations array, looking for a matching title, then select the relevant annotation : Open Map Annotation from Selected Row in Table View
Is this really the only way ? Since two pins could possibly share the same title, it seems a little bit hazardous...

The map view's annotations array is not guaranteed to return the annotations in the order that you added them.
This is partly due to the fact that if you have showsUserLocation set to YES, the annotations array returned by the map view includes the user location annotation even though you didn't explicitly call addAnnotation on it yourself. The map view adds that annotation internally so you have no control over the order.
The other reason is simply that the documentation doesn't say the array will be in any particular order.
See MKMapView annotations changing/losing order? for some more details.
As the answer you linked to suggests, one option is to search the annotations array until you find the one you're looking for that matches the criteria.
If your annotations are of type MKPointAnnotation, the only properties available are title, subtitle, and coordinate.
If these don't work for you (eg. if you can have annotations with the same title), you'll need to use a custom annotation class that has a property unique to each annotation.
However, note that the annotation class does not have to be a different class from your underlying data model class (eg. SPlaces).
It can simplify matters if your SPlaces class implements the MKAnnotation protocol itself. Then:
You won't need to loop through self.myPlaces and create separate annotation objects. Instead, you would have just the single line [self.myMap addAnnotations:self.myPlaces];.
You won't need to search through the map view's annotations array to find your SPlaces object. Instead, in didSelectRowAtIndexPath, you would be able to just do this:
[self.myMap selectAnnotation:[self.myPlaces objectAtIndex:row]
animated:YES];

Related

Reloading Google Map View when adding and removing markers

We are coding in Swift to create an application with UI buttons. These UI buttons will add or remove markers depending on its status. Because we want the buttons to be layered on top of google maps we have two view controllers. The top view controller contains a button. When the button is pressed, we want to remove the markers that have a "bad" status.
This is our code to remove the marker:
func showOnlyGood(){
mapView.clear() //this is the google map (GMSMapView.map)
for x in arrayOfGood { //Array of good markers
x.map = mapView //Set good markers to show
}
for y in arrayOfBad { //Array of bad markers
y.map = nil //removes markers from map
}
}
The google maps gets updated if the function call is in viewDidLoad(), but when we call the function in the top view controller with the buttons it does not update the map accordingly.
We think this is an issue with refreshing the google map view and have tried many different solutions, but the google map view only shows what is initially in viewDidLoad().
First, if you just want the buttons to be layered on top of the map, just add the buttons to the view after you've added the map to the view; do not create a second view controller. Your problem is most likely caused by this awkward setup. You also don't have an #objc prefix in your action method, which would definitely prevent the button from executing its action.
#objc func updateButtons() {
mapView.clear() // clear the map
for i in someArray {
let marker = GMSMarker()
// configure parameters
marker.map = mapView
}
}
That method will update your map's markers. There is [probably] never a need to refresh the map, even if you want to change styles.

Fetch the title of map dropped pin via MKPointAnnotation

I need to know how to fetch the title of a dropped pin. I have multiple dropped pins on the map, when the pin is tabbed I want to fetch the title to pass to prepareForSegue. I use this statement "let title = self.pointAnnotation.title" via (MKPointAnnotation) but I get the title of the last dropped pin and not the tabbed pin.
An easy and reliable way to get a reference to the annotation that was tapped is to use the map view's selectedAnnotations array: if let ann = self.mapView.selectedAnnotations[0] as? MKAnnotation {
println("(ann.title!)")
}

How can I remove all annotations on my MkMapView that are not currently visible on iOS 8

have a few annotations visible on my MkMapView using Swift 1.2 on iOS 8. Now if the user scrolls around the map, I'd like to remove all annotations, that are currently not visible.
How can I dow this?
First get the currently visible mapRect:
let visRect = mapView.visibleMapRect
now you can get all annotations within that rect:
let inRectAnnotations = mapView.annotationsInMapRect(visRect)
last step would be to iterate over all annotations and check if you annotation is in these annotations
for anno : MKAnnotation in mapView.annotations {
if (inRectAnnotations.contains(anno)) {
//do what you want to do with the annotation (hide/remove)
}
}

MKMapView with annotations issue

I have MKMapView with many annotations in proper order. And I have button to change map mode:
- (IBAction)userDidPressTrackButton:(id)sender {
if (self.mapView.userTrackingMode == MKUserTrackingModeFollow) {
self.mapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
return;
}
if (self.mapView.userTrackingMode == MKUserTrackingModeFollowWithHeading) {
self.mapView.userTrackingMode = MKUserTrackingModeNone;
return;
}
if (self.mapView.userTrackingMode == MKUserTrackingModeNone) {
self.mapView.userTrackingMode = MKUserTrackingModeFollow;
}
}
when mode = MKUserTrackingModeFollowWithHeading annotations begin to put themselves in random order. It seems that in this mode mapview begin to redraw itself every second and put all the subview (annotations) in unknown order.
How to cancel changing order of annotations?
The array of annotations that you get back from mapview.annotations is not guaranteed to be in the same order you that added them in. If you are relying on them vein in a special order you are probably doing your viewForAnnotations function wrong. It is given an annotation as a parameter, you use that to determine what view to draw. Usually people make a custom class that implements the MKAnnotation protocol and has some addition variables in which they store the data needed to create the right view. When viewForAnnotations gets called they check if the provided annotation is one of their special class, and if so extract the data, make the view and return it. There is no need to know the order of the annotations array, and it wouldn't do you any good because an MKMapView can and will ask for the annotations in any sequence it likes.
Side note: Why are you writing your own function for toggling the tracking mode? You can just use the official one and it will do it all for you.

Change the array of a UITableView

I´m using a table view to display different types of items. The view controller for the table is always the same, ItemsViewController.
I have a menu with buttons for each type of item. Depending on what button the user clicks, a specific array of items must be used to populate the table view.
My solution:
Every item has an typeId property. When a type button is clicked, the following method is called:
[self.itemController createItemListForId:buttonPressed.typeId];
where buttonPressed is, well, the pressed menu button.
This is the implementation for createItemListForId:
-(void)createItemListForId:(int)theId{
for (Item *item in self.masterItemList){
if(item.typeId == theId){
[self.itemList addObject:item];
}
}
}
The masterItemList is popluted with all the items at initialization.
My ItemsViewController uses the itemList to populate the cells.
The problem is that itemList is empty when the table view appears, so something not working with this method.
Any ideas on how to get this to work?

Resources