I have an application which shows something around 100 Annotations (with custom pin-images, callout accessories and annotation-images) in a MapView. While building the annotations I store a link between annotation and building so I can assign the right building and open the right segue afterwards.
In iOS 6 they get built really fast, I also enabled animation while adding them, so one pin got dropped after the other, but with apple maps in iOS7 this isn't possible anymore (?). Now building those 100 annotations takes over 1 second on my iPhone 4S and that's too long. Is there anyway to improve the code?
- (void)viewDidLoad
...
//creating annotations
annotationlink = [[NSMutableArray alloc] init];
for (int i = 0; i < data.count; i++) {
NSDictionary *dataItem = [data objectAtIndex:i];
//storing annotation in array for link
Annotation *buildingannotation = [[Annotation alloc] init];
NSNumber *index = [NSNumber numberWithInteger:i];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:index, indexKey, buildingannotation, annotationKey, nil];
[annotationlink addObject:dict];
buildingannotation.title = [dataItem objectForKey:#"Building"];
buildingannotation.subtitle = [dataItem objectForKey:#"Info"];
MKCoordinateRegion buildingcoordinates;
buildingcoordinates.center.latitude = [[dataItem objectForKey:#"Latitude"] floatValue];
buildingcoordinates.center.longitude = [[dataItem objectForKey:#"Longitude"] floatValue];
buildingannotation.coordinate = buildingcoordinates.center;
[self.mapView addAnnotation:buildingannotation];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
MKAnnotationView *pinView = (MKAnnotationView *)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:pinIdentifier];
MKAnnotationView *customAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinIdentifier];
customAnnotationView.canShowCallout = YES;
//right button to detail view
UIButton* disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
customAnnotationView.rightCalloutAccessoryView = disclosureButton;
//left button for image
NSInteger *buildingindex = [self getIndex:annotation];
NSDictionary *dataItem = [data objectAtIndex:buildingindex];
NSString* filename = [dataItem objectForKey:#"Thumb"];
filename = [filename stringByAppendingString:#"#2x.jpg"];
NSString* resourceimagePath = [resourcePath stringByAppendingPathComponent:filename];
Image = [UIImage imageWithContentsOfFile:resourceimagePath];
UIImageView *AnnotationThumb = [[UIImageView alloc] initWithImage:Image];
AnnotationThumb.frame = CGRectMake(0, 0, 31, 31);
customAnnotationView.leftCalloutAccessoryView = AnnotationThumb;
//annotation image
customAnnotationView.image = [UIImage imageNamed:#"Annotation_white.png"];
return customAnnotationView;
return pinView;
}
the following function gets the index of the current annotation using nspredicate to filter the array with the dictionaries. the advantage of this is the fact, that i can also use it when calloutAccessoryControlTapped:
-(NSInteger*) getIndex:(Annotation*)searchannotation
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K == %#", annotationKey, searchannotation];
NSArray *filteredarray = [annotationlink filteredArrayUsingPredicate:predicate];
NSDictionary *building = [filteredarray objectAtIndex:0];
NSInteger *buildingIndex = [[building objectForKey:indexKey] integerValue];
return buildingIndex;
}
With an iPhone 4S the last pin is built 1.14 seconds after the view gets loaded.
if i search the annotation link array manually instead of using nspredicate function like this:
//left button for image
int buildingIndex;
for (int i = 0; i < annotationlink.count; i++) {
NSDictionary *annotationDict = [annotationlink objectAtIndex:i];
if ([[annotationDict objectForKey:annotationKey] isEqual:annotation]) {
buildingIndex= [[annotationDict objectForKey:indexKey] integerValue];
i = annotationlink.count;
}
}
NSDictionary *dataItem = [data objectAtIndex:buildingIndex];
the log says that the last pin is built 1.89 seconds after the viewDidLoad.
if i create the annotations in viewDidApper instead of viewDidLoad the View is shown off course immediately but the background takes some time to load so until the pins are dropped everything is gray which is also not very nice...
Thank you Anna for your suggestions! I implemented the improvements like this:
Annotation.h:
#import <MapKit/MKAnnotation.h>
#interface Annotation : NSObject <MKAnnotation> {}
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#property NSInteger *ID;
#end
Annotation.m:
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate, title, subtitle, ID;
#end
ViewDidAppear:
//creating annotations
for (int i = 0; i < data.count; i++) {
NSDictionary *dataItem = [data objectAtIndex:i];
Annotation *buildingannotation = [[Annotation alloc] init];
buildingannotation.ID = i;
buildingannotation.title = [dataItem objectForKey:#"Building"];
buildingannotation.subtitle = [dataItem objectForKey:#"Subtitle"];
MKCoordinateRegion buildingcoordinates;
buildingcoordinates.center.latitude = [[dataItem objectForKey:#"Latitude"] floatValue];
buildingcoordinates.center.longitude = [[dataItem objectForKey:#"Longitude"] floatValue];
buildingannotation.coordinate = buildingcoordinates.center;
[self.mapView addAnnotation:buildingannotation];
}
viewForAnnotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
MKAnnotationView *pinView = (MKAnnotationView *)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:pinIdentifier];
if (pinView == nil) {
MKAnnotationView *customAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinIdentifier];
customAnnotationView.canShowCallout = YES;
//right button to detail view
UIButton* disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
customAnnotationView.rightCalloutAccessoryView = disclosureButton;
//left button for image
Annotation *buildingAnnotation = (Annotation *)annotation;
NSInteger *buildingindex = buildingAnnotation.ID;
NSString *filePath = [thumbname objectAtIndex:buildingindex];
UIImageView *AnnotationThumb = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:filePath]];
AnnotationThumb.frame = CGRectMake(0, 0, 31, 31);
customAnnotationView.leftCalloutAccessoryView = AnnotationThumb;
//annotation image
customAnnotationView.image = [UIImage imageNamed:#"Annotation_white.png"];
return customAnnotationView;
} else {
pinView.annotation = annotation;
}
return pinView;
}
Callout:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
Annotation *buildingAnnotation = (Annotation *)view.annotation;
selectedbuilding = buildingAnnotation.ID;
[self performSegueWithIdentifier:#"DetailViewController" sender:self];
}
Takes still some time for showing all Annotations. Is there any chance to further improve the code?
I updated the vievForAnnotation function regarding to Anna's reply and the PhotosByLocation Sample Application. It works now and I hope it's the correct way to implement the reuse...
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]]){
return nil;
}
MKAnnotationView *buildingAnnotationView = (MKAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:pinIdentifier];
if (buildingAnnotationView) {
[buildingAnnotationView prepareForReuse];
} else {
buildingAnnotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinIdentifier];
buildingAnnotationView.canShowCallout = YES;
//right button to detail view
UIButton* disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
buildingAnnotationView.rightCalloutAccessoryView = disclosureButton;
//annotation image
buildingAnnotationView.image = [UIImage imageNamed:#"Annotation_white.png"];
}
//left button for image
Annotation *buildingAnnotation = (Annotation *)annotation;
NSInteger *buildingindex = buildingAnnotation.ID;
NSString *filePath = [thumbname objectAtIndex:buildingindex];
UIImageView *AnnotationThumb = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:filePath]];
AnnotationThumb.frame = CGRectMake(0, 0, 31, 31);
buildingAnnotationView.leftCalloutAccessoryView = AnnotationThumb;
return buildingAnnotationView;
}
Related
I have a an array of latitude and longitude and using for loop am displaying the MKPointAnnotation on the map. I want to show a view as a popup with data when the specific MKPointAnnotation is tapped.
Here is my code -
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 10000, 10000);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
[_locationManager stopUpdatingLocation];
NSArray *set = [[NSArray alloc] init];
for (int i = 0; i < _json.count; i++) {
_name = [_json[i] valueForKey:#"name"];
_class = [_json[i] valueForKey:#"class"];
set = [_json[i] valueForKey:#"set"];
if (setFreeHour.count != 0) {
for (int j=0;j<set.count;j++) {
NSDictionary *dict = [[NSDictionary alloc] init];
dict = set[j];
_lat = dict[#"latitude"];
_longi = dict[#"longitude"];
CLLocationCoordinate2D coordinate;
coordinate.latitude = [_lat doubleValue];
coordinate.longitude = [_longi doubleValue];
// Add an annotation
MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
point1.coordinate = CLLocationCoordinate2DMake(coordinate.latitude, coordinate.longitude);
point1.title = _name;
point1.subtitle = _class;
[self.mapView addAnnotation:point1];
}
}
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
// Try to dequeue an existing pin view first.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView) {
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showDetails)];
[pinView addGestureRecognizer:tap];
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
- (void)showDetails{
self.popup.hidden = NO;
}
//PS: popup is a view that contains labels. I want to pass data from MKPointAnnotation to the view
Why don't you use mapView(_:didSelect:) method instead of UITapGestureRecognizer?
(void)mapView:(MKMapView *)mapview didSelectAnnotationView:(MKAnnotationView *)view {
// 1. get data from view(MKAnnotationView)
// 2. pass data to another view
}
https://developer.apple.com/documentation/mapkit/mkmapviewdelegate/1452393-mapview
I want to display different text on each annotationView, but same value is displayed on every annotation.
Following is my code :
NSMutableArray *strAnnoTitle;
-(void)callAddAnnotations{
cnt = 0;
[_mapView removeAnnotations:[_mapView annotations]];
for (id obj in arrPropTemp) {
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake([[[arrPropTemp valueForKey:#"Latitude"] objectAtIndex:cnt] floatValue], [[[arrPropTemp valueForKey:#"Longitude"] objectAtIndex:cnt] floatValue]);
strAnnoTitle[cnt] = [obj valueForKey:#"ListPriceForMap"];
// Add an annotation
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = coords;
[self.mapView addAnnotation:point];
cnt++;
}
}
-(MKAnnotationView *)createAnnotation:(MKAnnotationView *)viewAn{
UILabel *lbl = (UILabel *)[viewAn viewWithTag:100];
[lbl setText:strAnnoTitle[cnt]];
return viewAn;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *viewAn = [[[NSBundle mainBundle] loadNibNamed:#"MapAnnotation" owner:self options:nil] lastObject];
viewAn = [self createAnnotation:viewAn];
return viewAn;
return nil;
}
Output:
Where am I getting wrong? How do I solve this?
Change your implementation .
-(void)callAddAnnotations{
cnt = 0;
[_mapView removeAnnotations:[_mapView annotations]];
for (id obj in arrPropTemp) {
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake([[[arrPropTemp valueForKey:#"Latitude"] objectAtIndex:cnt] floatValue], [[[arrPropTemp valueForKey:#"Longitude"] objectAtIndex:cnt] floatValue]);
strAnnoTitle[cnt] = [obj valueForKey:#"ListPriceForMap"];
// Add an annotation
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = coords;
[point setTitle:strAnnoTitle[cnt]];
[self.mapView addAnnotation:point];
cnt++;
}
}
change your create method
-(MKAnnotationView *)createAnnotation:(MKAnnotationView *)viewAn{
UILabel *lbl = (UILabel *)[viewAn viewWithTag:100];
[lbl setText: viewAn.annotation.title];//can move this also to delegate
return viewAn;
}
Change your viewForAnnotation method to like this.
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *cabAnnotationIdentifier=#"cabAnnotationIdentifier";
MKAnnotationView * viewAn =[MapView dequeueReusableAnnotationViewWithIdentifier:cabAnnotationIdentifier];
if(!annotationView){
MKAnnotationView *viewAn = [[[NSBundle mainBundle] loadNibNamed:#"MapAnnotation" owner:self options:nil] lastObject];
viewAn = [self createAnnotation:viewAn];
}
return viewAn;
}
Take 1 NSObject file with the required fields u want for annotation. Add annotation on mapview and attach information on that Nsobject file also and same do as in viewforannotation method it will work.
Like
1.) NSObject file
REVPin.h
#interface REVPin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSInteger tag;
NSArray *nodes;
}
#property(nonatomic, retain) NSArray *nodes;
#property(readwrite, nonatomic) NSInteger tag;
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
-(void)AddPinToMap:(NSMutableArray *)PinArray
{
NSMutableArray *pins = [NSMutableArray array];
oldZoomLevel = (int)[self zoomLevelForMapRect:MapView.visibleMapRect withMapViewSizeInPixels:CGSizeMake(MapView.frame.size.width, MapView.frame.size.height)];
if ([isFirstTimeN isEqualToString:#"YES"]) {
[MapView removeAnnotations:MapView.annotations];
for(int i=0;i<[PinArray count];i++) {
CGFloat latitude=[[[PinArray objectAtIndex:i] objectForKey:#"lat"] floatValue];
CGFloat longitude=[[[PinArray objectAtIndex:i] objectForKey:#"lon"] floatValue];
CLLocationCoordinate2D newCoord = {latitude, longitude};
REVPin *pin = [[REVPin alloc] init];
pin.title = [NSString stringWithFormat:#"Pin %i",i+1];
pin.subtitle = [NSString stringWithFormat:#"Pin %i subtitle",i+1];
pin.coordinate = newCoord;
pin.tag = i;
pin.userId = [NSString stringWithFormat:#"%#",[[PinArray objectAtIndex:i] objectForKey:#"u"]];
[pins addObject:pin];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
REVPin *pin = (REVPin *)annotation;
MKAnnotationView *annView;
if([annotation class] == MKUserLocation.class)
{
return nil;
}
annView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"pin"];
annView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"pin"];
[array addObject:pin];
return annView;
}
try by using above way it will work
I am new to xcode and i hope someone can help me with my code, and point me how to solve my issue. i've been looking at the internet, but really i couldnt figure it out.
How can i go from a map view to a detail view, bringing the "ID" of the pin with it and print it in a label.
when i click on the arrow for the annotation, my simulator crashes.
Please any ideas, how to approach it and solve it ?
( basicly i want to get the ID of the pin, and send it to a server through JSON and then move to the Detailview, but the next step )
Here is what i did so far :
My Location.m ( view controller for the map )
#import "My_Location.h"
#import "DetailViewController.h"
// ------ FUNCTION TO GET COORDINATES IN JSON FORMAT -------
- (void)retrieveData_Location
{
NSURL * url = [NSURL URLWithString:#"............./Pharmacies.php"];
NSData * data = [NSData dataWithContentsOfURL:url];
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSMutableArray *newAnnotations = [NSMutableArray array];
CLLocationCoordinate2D location;
for (NSDictionary *dictionary in array)
{
MKPointAnnotation *newAnnotation = [[MKPointAnnotation alloc] init];
location.latitude = [dictionary[#"lat"] doubleValue];
location.longitude = [dictionary[#"lon"] doubleValue];
newAnnotation.title = dictionary[#"name"];
newAnnotation.coordinate = location;
[newAnnotations addObject:newAnnotation];
[newAnnotation release];
}
[self.MyLocation addAnnotations:newAnnotations];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation {
if([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *identifier = #"myAnnotation";
MKPinAnnotationView * annotationView = (MKPinAnnotationView*)[self.MyLocation dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.pinColor = MKPinAnnotationColorPurple;
annotationView.animatesDrop = YES;
annotationView.canShowCallout = YES;
}else {
annotationView.annotation = annotation;
}
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
[self performSegueWithIdentifier:#"Details" sender:view];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Details"])
{
MKAnnotationView *annotationView = sender;
[segue.destinationViewController setAnnotation:annotationView.annotation];
}
}
Take_Photo is my detailviewcntroller.
And my storybaord look like this :
Mylocation View controller -> ( Segue: identifier ( Take_Photo )) -> Take_Photo view Controller
My MKAnnotationView delegate method is been called as I can see my NSLog output. However the pins are not appearing on the map. Is there something I'm missing here?
MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *nearbyMapView;
#end
MapViewController.m
#import "MapViewController.h"
#import "AppDelegate.h"
#interface MapViewController ()
#end
#implementation MapViewController
AppDelegate *appDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate=[[UIApplication sharedApplication] delegate];
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(54.995184, -1.566699);
MKCoordinateSpan span = MKCoordinateSpanMake(0.5, 0.5);
MKCoordinateRegion regionToDisplay = MKCoordinateRegionMake(center, span);
[self.nearbyMapView setRegion: regionToDisplay];
for (int i = 0; i < [[appDelegate offersFeeds] count]; i++) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
NSString *plotAddress = [[[appDelegate offersFeeds] objectAtIndex:i] valueForKey:#"addressline"];
NSString *plotTitle = [[[appDelegate offersFeeds] objectAtIndex:i] valueForKey:#"title"];
[geocoder geocodeAddressString:plotAddress completionHandler:^(NSArray *placemarks, NSError *error) {
if (placemarks && placemarks.count > 0)
{
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc]initWithPlacemark:topResult];
MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
pa.coordinate = placemark.location.coordinate;
pa.title = plotTitle;
[self.nearbyMapView addAnnotation:pa];
}
}];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
MKAnnotationView *pinView = nil;
static NSString *defaultPinID = #"identifier";
pinView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil ) {
NSLog(#"Inside IF");
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
pinView.enabled = YES;
pinView.canShowCallout = YES;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
//Accessoryview for the annotation view in ios.
pinView.rightCalloutAccessoryView = btn;
}
else {
pinView.annotation = annotation;
}
pinView.annotation = annotation;
return pinView;
}
#end
In viewForAnnotation, the code is creating an MKAnnotationView but not setting an image for it. There is no default image on an MKAnnotationView so the annotations are invisible.
When you don't implement the delegate at all, the map view creates MKPinAnnotationViews for you with a red pin color. MKPinAnnotationView is a convenient subclass of MKAnnotationView which supplies a pin image (in one of three colors).
When you implement the delegate, it's up to you to create the right view and set the properties as needed.
Either create an MKPinAnnotationView instead (which provides a default pin image) or set the image property on the plain MKAnnotationView.
To use MKPinAnnotationView:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinView = nil;
static NSString *defaultPinID = #"identifier";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
{
NSLog(#"Inside IF");
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
pinView.pinColor = MKPinAnnotationColorRed; //or Green or Purple
pinView.enabled = YES;
pinView.canShowCallout = YES;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
//Accessoryview for the annotation view in ios.
pinView.rightCalloutAccessoryView = btn;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
or to use MKAnnotationView and your own image:
//same code as the current but add this line
//after the initWithAnnotation:
pinView.image = [UIImage imageNamed:#"SomeImage.png"];
I have the following files:
annotation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface annotation : NSObject <MKAnnotation>
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#end
annotation.m:
#import "annotation.h"
#implementation annotation
#synthesize coordinate, title, subtitle;
#end
And in the main code, which takes in an NSURL found elsewhere:
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[spinner stopAnimating];
// json parsing
results = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil];
NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
annotation * myAnn;
NSArray *pins = mapView.annotations;
if ([pins count])
{
[mapView removeAnnotations:pins];
}
/* loop through the array, each key in the array has a JSON String with format:
* title <- string
* strap <- string
* id <- int
* date <- date
* lat <- floating point double
* long <- floating point double
* link <- string
*/
int i;
for (i = 0; i < [results count]; i++) {
//NSLog(#"Result: %i = %#", i, results[i]);
//NSLog(#"%#",[[results objectAtIndex:i] objectForKey:#"long"]);
myAnn = [[annotation alloc] init];
location.latitude = (double)[[[results objectAtIndex:i] objectForKey:#"lat"] doubleValue];
location.longitude = (double)[[[results objectAtIndex:i] objectForKey:#"long"] doubleValue];
myAnn.coordinate = location;
myAnn.title = [[results objectAtIndex:i] objectForKey:#"title"];
myAnn.subtitle = [[results objectAtIndex:i] objectForKey:#"strap"];
[locations addObject:myAnn];
//NSLog(#"%i", [[results objectAtIndex:i] objectForKey:#"lat"]);
}
[self.mapView addAnnotations:locations];
Previous things I have looked at for this say that I need to use MKAnnotationView as opposed to MKPinAnnotationView but as you can see I do not use either, is it possible for me to use custom images for the pins that are dropped on the screen.
You (a) make sure to define your view controller to be the delegate for your MKMapView; and (b) implement viewForAnnotation, e.g.:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
static NSString * const identifier = #"MyCustomAnnotation";
MKAnnotationView* annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView) {
annotationView.annotation = annotation;
} else {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier];
}
// set your annotationView properties
annotationView.image = [UIImage imageNamed:#"Your image here"];
annotationView.canShowCallout = YES;
// if you add QuartzCore to your project, you can set shadows for your image, too
//
// [annotationView.layer setShadowColor:[UIColor blackColor].CGColor];
// [annotationView.layer setShadowOpacity:1.0f];
// [annotationView.layer setShadowRadius:5.0f];
// [annotationView.layer setShadowOffset:CGSizeMake(0, 0)];
// [annotationView setBackgroundColor:[UIColor whiteColor]];
return annotationView;
}
return nil;
}
By the way, in my example above, I changed the name of your annotation class to CustomAnnotation. annotation is a horrible name for a class because (a) it doesn't follow class naming conventions of upper case first letter; and (b) it's identical to the variable name, annotation, that many MKMapViewDelegate methods will use by default.
References
Location Awareness Programming Guide
Map Kit Framework Reference
You can certainly use custom images for an MKAnnotationView, see iOS MapKit custom pins.
Both MKAnnotationPinView and MKAnnotationView are subclasses of UIView and therefore will allow custom views.