Reload mapView with new pins iphone dev? - iphone

I am developing an application in which i need to show multiples events location at same time and i have two types of events(my events and all events). I give opportunity to switch between my events and all events through segment control, First it show all events location and when user switch to my events it'll delete or hide all events location(pins) and show my events location pins on same map view. I've bit confusion how to handle this to reload or refresh map view with new pins?

You may try this...
//Remove or hide all annotations
for (id annotation in mapView.annotations) {
if (annotation != mapView.userLocation) {
[[mapView viewForAnnotation:annotation] setHidden:YES]; // You can remove as well
}
}
/code to remove annotations instead of hiding/
NSMutableArray *listRemoveAnnotations = [[NSMutableArray alloc] init];
for (id annotation in mapView.annotations) {
if (annotation != mapView.userLocation) {
[listRemoveAnnotations addObject:annotation];
}
}
[mapView removeAnnotations:listRemoveAnnotations];
[listRemoveAnnotations release];
When all annotations are dealt with then:
if all annotations are hidden, un-hide the annotations you wish to show.
if all annotations are removed, add annotations you wish to show.

Related

Duplicated MKAnnotations when charging web service in xCode

I make annotations from a response JSON from a Web service.
I can load the pins in the map, but when I move the position of the center I have to reload a new bunch of annotations and delete the old ones. When I do the method it only charges the pins and if I move the center it does the same and recharge.
I've tried a lot of methods like this one...
for (id<MKAnnotation> annotation in _mapView.annotations) {
[_mapView removeAnnotation:annotation];
}
But it only, does this: I gets to the center of the map and when I move the map it returns to the start and I can't zoom the map cause it reloads and loops.
To remove all annotations, just run this before you add the new ones..
NSMutableArray *toRemove = [NSMutableArray arrayWithCapacity:15];
for (id annotation in mapView.annotations){
if (annotation != mapView.userLocation)
[toRemove addObject:annotation];
[mapView removeAnnotations:toRemove];

MKMapView annotations changing/losing order?

I have a map view with annotations, and these annotations display a callout. When the callout's disclosure detail button is clicked, it segues into a new view.
My MKAnnotations are a custom class that implements <MKAnnotation>. Let's call that class MyClass. They are stored in an NSMutableArray. During viewdidload of this view, I add each object of MyClass in this array to the map view's annotations. Using the debugger, I can see that once all of this adding is done, the [self.MapView annotations] order is the same as the NSMutableArray.
Now I set another breakpoint within mapView:viewForAnnotation: and check out the order of 1) my NSMutableArray and 2) [self.MapView annotations]. The array is of course in the same order. However, the order of the annotations has been scrambled.
This was a big problem for me, because I needed to use the specific instance of MyClass that the user selected in the next view. AKA, I wanted to look at the annotation, find its index, and then use that to get the same index within the array.
I've now realized that I can just save the annotation directly (coming from an Android background, this was very cool to me). However, I am still conceptually at a loss as to why the order became scrambled. Can someone help me? Code below:
- (void)viewDidLoad
{
if([fromString isEqualToString:#"FromList"])
self.navigationItem.hidesBackButton = TRUE;
else {
self.navigationItem.rightBarButtonItem = nil;
}
self.array = [MySingleton getArray];
//set up map
//declare latitude and longitude of map center
CLLocationCoordinate2D center;
center.latitude = 45;
center.longitude = 45;
//declare span of map (height and width in degrees)
MKCoordinateSpan span;
span.latitudeDelta = .4;
span.longitudeDelta = .4;
//add center and span to a region,
//adjust the region to fit in the mapview
//and assign to mapview region
MKCoordinateRegion region;
region.center = center;
region.span = span;
MapView.region = [MapView regionThatFits:region];
for(MyClass *t in self.array){
[MapView addAnnotation:t];
}
[super viewDidLoad];
}
//this is the required method implementation for MKMapView annotations
- (MKAnnotationView *) mapView:(MKMapView *)thisMapView
viewForAnnotation:(MyClass *)annotation
{
static NSString *identifier = #"MyIdentifier";
//the result of the call is being cast (MKPinAnnotationView *) to the correct
//view class or else the compiler complains
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[thisMapView
dequeueReusableAnnotationViewWithIdentifier:identifier];
if(annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
}
annotationView.pinColor = MKPinAnnotationColorGreen;
//pin drops when it first appears
annotationView.animatesDrop=TRUE;
//tapping the pin produces a gray box which shows title and subtitle
annotationView.canShowCallout = YES;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.rightCalloutAccessoryView = infoButton;
return annotationView;
}
When you call addAnnotation or addAnnotations, the map view adds the reference(s) to its internal list of annotations.
The annotations property of MKMapView simply returns this internal list (whatever type it might be) as an NSArray.
I don't know of any place in the documentation where it states that the annotations property returns the array in the same order that you added the annotations in. If you have showsUserLocation turned on, the array will include that annotation even though you didn't explicitly add it.
You do not need to be concerned about nor should you depend on the order of the objects in the annotations property.
Just a few suggestions regarding the code:
Since your array contains objects that implement <MKAnnotation>, instead of looping through it, you can add all the annotations in one shot by calling addAnnotations (plural) and pass it the array
In viewForAnnotation, none of the properties you are setting depend on any specific annotation so you can set them all inside the if (av == nil) block. This way you get maximum reuse.
Also in viewForAnnotation, after and outside the if, you should set the annotation property of the view to the current annotation. This is in case the view is being reused from another annotation.
Finally, in viewForAnnotation, don't assume the annotation will be of type MyClass. If you turn on showsUserLocation, that won't be the case. It's safer to declare the parameter as id<MKAnnotation> and then if necessary check what its class is and then cast it.
#Anna, you state you should not be concerned for the order of the annotations. That's not true in my case. Some annotationviews might overlap, and I always need a specific one to be on the top of the two overlapping views. So the order DO makes sense for the annotations, as I hope the - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation gets called in the same order as i added the annotations.
EDIT:
and the solution is here :-)

Adding UIButtonTypeDetailDisclosure - Logic issue

I have added a annotaion pin point to my application, and when the user clicks on the pin, the popup appears with the blue arrow on it (UIButtonTypeDetailDisclosure). Now what i want to do is, when the user clicks on it i need the view to redirect to another view with the more details about it.
for example: If its a Hospital that i click, and the popup will give its name and the UIButtonTypeDetailDisclosure button. When i click on the UIButtonTypeDetailDisclosure button, i should redirect to another view whcih gives more information about that hospital.
My code:
-(void)callingMap:(NSArray *)hospitalArray {
for(Hospital *hospital in hospitalArray)
{
MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = hospital.lati;
region.center.longitude = hospital.longi;
[self.mapView setRegion:region animated:YES];
DetailMap *hospitalInfo = [[DetailMap alloc] init];
hospitalInfo.title = [hospital name];
hospitalInfo.subtitle = [hospital address];
hospitalInfo.coordinate = region.center;
[self.mapView addAnnotation:hospitalInfo];
}
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:
(id <MKAnnotation>)annotation {
MKAnnotationView* ann = nil;
if(annotation != mapView.userLocation)
{
ann = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"try"];
ann.canShowCallout = YES;
ann.image = [UIImage imageNamed:#"arrow.png"];
UIButton* butt = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[butt addTarget:self action:#selector(displayArrow:) forControlEvents:
UIControlEventTouchUpInside];
ann.rightCalloutAccessoryView = butt;
}
return ann;
}
-(void)displayArrow:(id)sender{
MoreHospitalDetailViewController *mhdvc = [[MoreHospitalDetailViewController alloc] initWithNibName:nil bundle:nil];
mhdvc.hospitalArray = ????????
// in the MoreHospitalDetailViewController i have an Array called hospitalArray. I need to insert the selected hospital object (after clicking the particular arrow) to this array and pass it to the next view. How to do it ? //
[self.navigationController pushViewController:mhdvc animated:YES];
}
In the MoreHospitalDetailViewController i have an Array called hospitalArray. I need to insert the selected hospital object (after clicking the particular arrow) to this array and pass it to the next view. How to do it ?
note: There can be many items (annotations) in the map, so how do i know which hospital Object i clicked when i am in the (void)displayArrow:(id)sender method ?
Help i am lost
In the displayArrow: method, you can get a reference to the annotation that was clicked using:
DetailMap *hospitalInfo
= (DetailMap *)[mapView.selectedAnnotations objectAtIndex:0];
Note you can also use the map view's calloutAccessoryControlTapped delegate method instead of doing addTarget and writing a custom method. For example:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
DetailMap *hospitalInfo = (DetailMap *)view.annotation;
//do something with the annotation...
}
You have two classes:
Hospital which contains the full details of a hospital including phone#, etc.
DetailMap which implements MKAnnotation and contains just a hospital's coordinate, name, and address (but not the phone# or anything else)
When tapping the callout button of an annotation, you want to get access to the full hospital info (not just coordinate, name, and address).
First, when you say in the comments "DetailMap which only contains 2 records", you really mean "fields" or "properties" instead of "records" (each hospital object is a "record").
Here are a couple of ways to solve this:
In DetailMap, add a property called say hospital of type Hospital and set it when creating DetailMap objects in the callingMap method (hospitalInfo.hospital = hospital). Then in the displayArrow: method, you can add that property to the array (mhdvc.hospitalArray = [NSArray arrayWithObject:hospitalInfo.hospital];).
Change the Hospital class so that it implements MKAnnotation itself and eliminate the DetailMap class entirely. Then you can directly pass Hospital objects to addAnnotation and in the displayArrow: method you would do this:
Hospital *hospital = (Hospital *)[mapView.selectedAnnotations objectAtIndex:0];
mhdvc.hospitalArray = [NSArray arrayWithObject:hospital];
The first option is easier since you've already created the DetailMap class but the second one is cleaner.
Still, the MoreHospitalDetailViewController doesn't need an array to pass the single hospital object (which contains multiple fields). You could just declare a Hospital *hospital property in MoreHospitalDetailViewController to pass the single object.

iOS rotating MKAnnotationView in response of MKMapView rotation

In my application I have a MKMapView where several annotations are shown. The map rotates based on the heading of the device. To rotate the map the following statement is performed (called by the method locationManager: didUpdateHeading:)
self.navigationMapView.mapView.transform = CGAffineTransformMakeRotation(-heading);
where the heading (magnetic) is expressed in radians. What I noticed it's that even the annotations in the map rotate and I don't want it. I tried to fix it in the following method:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *identifier = #"AnnotationViewIdentifier";
MKAnnotationView *av = [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (av == nil) {
av = [[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:identifier] autorelease];
}
else{
av.annotation = annotation;
}
av.transform = CGAffineTransformMakeRotation(degreesToRadians(self.arController.currentHeading.magneticHeading));
av.canShowCallout = YES;
return av;
}
and I want to call this method from "didUpdateHeading:" but I really don't know how to do it. The TableView class has the reloadData function that calls the delegate method but here the things seem different. Any suggestions?!
Another question, my annotations on the map show the distance from the user, I would like to update them (distance label) as soon as the user change location. Any suggestions?!
So with a MKMapView having that be called properly is a little bit annoying. Essentially you have one of two options. Option 1: Create an array of the annotation on the screen and remove that from the map_view and then re-add them to the map_view. Essentially creating your own reload data function. Option 2: Do something simple such as
CGLocationCoordinate2D coordinate = map_view.center;
map_view.center = coordinate;
-- Essentially the point is to reset a property of the map causing it to redraw. However this option is not always going to work. Option 1 has a higher chance of working however that one can also fail, so if simply taking the annotations off and re-adding them causes nothing to happen then simply decreate the map and then recreate the map at the end of your map refresh function something like.
[my_map_view removeFromSuperView];
[my_map_view release];
my_map_view = nil;
my_map_view = [[MKMapView alloc] initWithFrame:CGRectMake(0,0,320,480)];
one of these options should work. I had to do option one for my solution however I know some people are lucky and option 2 works just as well.

show map callout through code in iPhone

I have tried several things but am unable to solve it out.
I have 10 custom annotations on the map depending upon the area visible.
Now I have 2 buttons next and previous. Clicking on which the callout of annotation must get displayed.
i.e if i click on next buton then callout of annotation 1 will appear and when i click next again then the callout of first will hide and callout of second will appear.
I have tried out
[self.mapView selectAnnotation:self.nextSelectedAnnotationView.annotation animated:YES]
and
[self.mapView deselectAnnotation:self.selectedAnnotationView.annotation animated:YES];
But the main problem is how to get the annotation here??
I have tried NSArray* selectedAnnotations=self.mapview.annotations to get the annotations array
id annotationView =[selectedAnnotations objectAtIndex:i];
[self.mapView selectAnnotation:annotationView animated:YES];
But no luck :(
Any other way to solve my issue.??
it may help you.
NSArray *selectedAnnotations = mapView.selectedAnnotations;
for(id annotationView in selectedAnnotations) {
[mapView deselectAnnotation:[annotationView annotation] animated:NO];
}