I've been developing an application these last few days, but has come across a stop.
So, what i want to do is display annotations on a map, with location data from an XML. There are data there for 150 pins in norway.
What i have understanded, is that you need to build your own class for each MKAnnotations? I cant have hundreds of classes
I am fairly new to Obj-C, but is learning this quickly!
I came up with a loop to loop trough my values in the XML.
Code:
for (int i = 0; i < 140; i++) {
Camera *aCamera = [appDelegate.cameras objectAtIndex:i];
NSLog(@"Latitude%d: %d Longtitude: %d", i, aCamera.lat, aCamera.longt);
}
I've been developing an application these last few days, but has come across a stop.
So, what i want to do is display annotations on a map, with location data from an XML. There are data there for 150 pins in norway.
What i have understanded, is that you need to build your own class for each MKAnnotations? I cant have hundreds of classes
I am fairly new to Obj-C, but is learning this quickly!
Really hope someone can help me
No, you don't create a separate CLASS for each annotation. You create a separate annotation object for each annotation, and they are generally ALL of the same class. (If you had an app that displayed different types of annotations, like businesses, government buildings, museums, etc, you might want different types of data for each, in which case you might decide to have different types of annotation objects to store the data for each.)
Map annotations are simple data objects. They can be any object that supports the MKAnnotation protocol. The only requirement for an annotation is that it have a -coordinate property. It can also have optional title and subtitle properties.
Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.
Okay, now i stumbled upon a new problem, a bit more difficult.
I am trying to add an action when clicking on the annotation callout. (If that is what it's called). You know, that blue arrow.
Okay, so here are some code:
Here are the annotations added
Code:
for (int i = 0; i < 140; i++) {
Camera *aCamera = [appDelegate.cameras objectAtIndex:i];
NSLog(@"Road%d: %@", i, aCamera.lat);
cameraMapViewController* anAnnotation = [[[cameraMapViewController alloc] init] autorelease];
CLLocationDegrees latitude;
CLLocationDegrees longtitude;
latitude = [aCamera.lat doubleValue];
longtitude = [aCamera.longt doubleValue];
coordinate.latitude = latitude;
coordinate.longitude = longtitude;
anAnnotation.title = aCamera.road;
anAnnotation.subtitle = aCamera.region;
anAnnotation.coordinate = coordinate;
[cameraMap addAnnotation: anAnnotation];
}
And here are the custom pin-view made:
Code:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
customPinView.pinColor = MKPinAnnotationColorRed;;
customPinView.animatesDrop = NO;
customPinView.canShowCallout = YES;
// add a detail disclosure button to the callout which will open a new view controller page
//
// note: you can assign a specific call out accessory view, or as MKMapViewDelegate you can implement:
// - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control;
//
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:@selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
*** you see, the button triggers the showDetails-function, which you can see here:
Code:
- (void)showDetails:(id)sender
{
appDelegate = (VeikameraAppDelegate *)[[UIApplication sharedApplication] delegate];
// the detail view does not want a toolbar so hide it
camController = [[showCameraViewController alloc] initWithNibName:@"showCameraViewController" bundle:[NSBundle mainBundle]];
Camera *aCamera = [appDelegate.cameras objectAtIndex:sender];
camController.aCamera = aCamera;
[self.navigationController pushViewController:camController animated:YES];
[camController release];
//NSLog(@"showDetails, id:%d", sender);
}
So, the problem is that the ID its returning to showDetails(the sender) is of no use for me. I need a integer between 1 and 149(numer of annotations there are). Is it in some way possible to stick each annotation with it's own id? :-)
Okay, now i stumbled upon a new problem, a bit more difficult.
I am trying to add an action when clicking on the annotation callout. (If that is what it's called). You know, that blue arrow.
Okay, so here are some code:
Here are the annotations added
Code:
for (int i = 0; i < 140; i++) {
Camera *aCamera = [appDelegate.cameras objectAtIndex:i];
NSLog(@"Road%d: %@", i, aCamera.lat);
cameraMapViewController* anAnnotation = [[[cameraMapViewController alloc] init] autorelease];
CLLocationDegrees latitude;
CLLocationDegrees longtitude;
latitude = [aCamera.lat doubleValue];
longtitude = [aCamera.longt doubleValue];
coordinate.latitude = latitude;
coordinate.longitude = longtitude;
anAnnotation.title = aCamera.road;
anAnnotation.subtitle = aCamera.region;
anAnnotation.coordinate = coordinate;
[cameraMap addAnnotation: anAnnotation];
}
And here are the custom pin-view made:
Code:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
customPinView.pinColor = MKPinAnnotationColorRed;;
customPinView.animatesDrop = NO;
customPinView.canShowCallout = YES;
// add a detail disclosure button to the callout which will open a new view controller page
//
// note: you can assign a specific call out accessory view, or as MKMapViewDelegate you can implement:
// - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control;
//
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:@selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
*** you see, the button triggers the showDetails-function, which you can see here:
Code:
- (void)showDetails:(id)sender
{
appDelegate = (VeikameraAppDelegate *)[[UIApplication sharedApplication] delegate];
// the detail view does not want a toolbar so hide it
camController = [[showCameraViewController alloc] initWithNibName:@"showCameraViewController" bundle:[NSBundle mainBundle]];
Camera *aCamera = [appDelegate.cameras objectAtIndex:sender];
camController.aCamera = aCamera;
[self.navigationController pushViewController:camController animated:YES];
[camController release];
//NSLog(@"showDetails, id:%d", sender);
}
So, the problem is that the ID its returning to showDetails(the sender) is of no use for me. I need a integer between 1 and 149(numer of annotations there are). Is it in some way possible to stick each annotation with it's own id? :-)
There are a couple of solutions. You can add a numeric tag to the rightButton object that you add to the rightCalloutAccessoryView (UIButtons have a tag property.) Then, in your action, you can get the sender's tag property to retrieve the index.
The problem with that approach is that if you, or the user, does anything to change the numbering of your annotations, like deleting one of them, the indexes are not valid any more.
A better option would be to use the map view delegate calloutAccessoryControlTapped method. That method gives you a pointer to the annotation view which, in turn, gives you a pointer to the annotation object itself.
By the way, I see what looks like a big problem with the code you posted. You create your annotations with the following line of code:
The name of the class you are using, "cameraMapViewController", suggests that you are creating a view controller object as an annotation. That would be very bad. View controllers are big complex objects, intended to manage a whole screen-full of views, respond to user interface rotations, handle low memory warnings, etc.
If your annotation objects are simple data container objects, and not view controllers, then the class name is a bad choice. You should call it something like cameraMapAnnotation.
Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.