How to add annotations to MKMapView asynchronously? - iphone

I have a lot of annotations to be added to a mkmapview. When i add the annotations, the app freezes for a short period of time. I have understand that the main thread is the only thread allowed to add UI to view, if this is true, how to i make this operation not freeze the app?
// in viewdidLoad
for (NSManagedObject *object in requestResults) {
CustomAnnotation *customAnnotation = [[CustomAnnotation alloc] init];
customAnnotation.title = object.title;
customAnnotation.coordinate = CLLocationCoordinate2DMake([object.latitude doubleValue], [object.longitude doubleValue]);
[_mapView addAnnotation:customAnnotation];
}
} // end viewdidload
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// shows the annotation with a custom image
MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"mapAnnotation"];
CustomAnnotation *customAnnotation = (id) annotation;
customPinView.image = [UIImage imageNamed:#"green"];
return customPinView;
}

You can use Grand Central Dispatch - GCD for doing this.
Try with:
- (void)viewDidLoad
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (NSManagedObject *object in requestResults)
{
CustomAnnotation *customAnnotation = [[CustomAnnotation alloc] init];
customAnnotation.title = object.title;
customAnnotation.coordinate = CLLocationCoordinate2DMake([object.latitude doubleValue], [object.longitude doubleValue]);
dispatch_async(dispatch_get_main_queue(), ^{
[_mapView addAnnotation:customAnnotation];
});
}
});
}
This is a nice tutorial: GCD and threading

Even better & simpler, check out -[MKMapView addAnnotations:] to bulk add without the recalculation overhead of each individual annotation.

Related

How to add 'Maps' app link to each of my map annotations

There are a few tutorials and questions on this, but I'm not knowledgeable enough yet to understand how to implement them into my particular app. I get JSON annotation data from a URL and parse it and add each annotation in for loop. I want to add a link on each annotation to open Maps for directions.
Here's my ViewController.H
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import <MapKit/MapKit.h>
//MAP Setup
#interface ViewController : UIViewController <MKMapViewDelegate>
//map setup
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic, strong) NSMutableData *downloadData;
//- (IBAction)refreshTapped:(id)sender;
#end
and my ViewController.m
- (void)viewDidLoad
{
////////////////////////
//Connection to download JSON map info
////////////////////////
self.downloadData = [NSMutableData new];
NSURL *requestURL2 = [NSURL URLWithString:#"http:OMITTED"];
NSURLRequest *request = [NSURLRequest requestWithURL:requestURL2];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
//scroller
[scroller setScrollEnabled:YES];
[scroller setContentSize:CGSizeMake(320,900)];
[super viewDidLoad];
//Map
[self.mapView.userLocation addObserver:self
forKeyPath:#"location"
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
context:nil];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.downloadData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
id parsed = [NSJSONSerialization JSONObjectWithData:_downloadData options:kNilOptions error:nil];
////////////////////////
//Iterating and adding annotations
////////////////////////
for (NSDictionary *pointInfo in parsed)
{
NSLog([pointInfo objectForKey:#"name"]);
double xCoord = [(NSNumber*)[pointInfo objectForKey:#"lat"] doubleValue];
double yCoord = [(NSNumber*)[pointInfo objectForKey:#"lon"] doubleValue];
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(xCoord, yCoord);
MKPointAnnotation *point = [MKPointAnnotation new];
point.coordinate = coords;
point.title = [pointInfo objectForKey:#"name"];
[self.mapView addAnnotation:point];// or whatever your map view's variable name is
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//centers map on user loc and then allows for movement of map without re-centering on userlocation check.
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([self.mapView showsUserLocation])
{
MKCoordinateRegion region;
region.center = self.mapView.userLocation.coordinate;
MKCoordinateSpan span;
span.latitudeDelta = .50; // Change these values to change the zoom
span.longitudeDelta = .50;
region.span = span;
[self.mapView setRegion:region animated:YES];
self.mapView.showsUserLocation = NO;}
}
- (void)dealloc
{
[self.mapView.userLocation removeObserver:self forKeyPath:#"location"];
[self.mapView removeFromSuperview]; // release crashes app
self.mapView = nil;
}
#end
Launching the Maps App of the Location Awareness Programming Guide says:
If you would prefer to display map information in the Maps app as opposed to your own app, you can launch Maps programmatically using one of two techniques:
In iOS 6 and later, use an MKMapItem object to open Maps.
In iOS 5 and earlier, create and open a specially formatted map URL as described in Apple URL Scheme Reference.
The preferred way to open the Maps app is to use the MKMapItem class. This class offers both the openMapsWithItems:launchOptions: class method and the openInMapsWithLaunchOptions: instance method for opening the app and displaying locations or directions.
For an example showing how to open the Maps app, see “Asking the Maps App to Display Directions.”
So, you should:
Make sure to define your view controller to be the delegate for your map view;
Write a viewForAnnotation that turns on canShowCallout and turns on the callout accessory view:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView* annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"MyCustomAnnotation"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
Then write a calloutAccessoryControlTapped method that opens the maps as outlined above, based upon what versions of iOS you're supporting, e.g., for iOS 6:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
id <MKAnnotation> annotation = view.annotation;
CLLocationCoordinate2D coordinate = [annotation coordinate];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinate addressDictionary:nil];
MKMapItem *mapitem = [[MKMapItem alloc] initWithPlacemark:placemark];
mapitem.name = annotation.title;
[mapitem openInMapsWithLaunchOptions:nil];
}
I don't know what additional geographic information your have in your KML, but you can presumably fill in the addressDictionary as you see fit.
In answer to your follow-up question about how to use the addressDictionary parameter of the MKPlacemark initializer method, initWithCoordinate, if you had NSString variables for the street address, the city, the state, the zip, etc., it would look like:
NSDictionary *addressDictionary = #{(NSString *)kABPersonAddressStreetKey : street,
(NSString *)kABPersonAddressCityKey : city,
(NSString *)kABPersonAddressStateKey : state,
(NSString *)kABPersonAddressZIPKey : zip};
For this to work, you have to add the appropriate framework, AddressBook.framework, to your project and import the header in your .m file:
#import <AddressBook/AddressBook.h>
The real question, though, was how to set the name for the MKMapItem so it doesn't show up as "Unknown Location" in the maps app. That's as simple as setting the name property, probably just grabbing the title from your annotation:
mapitem.name = annotation.title;

The rightCalloutAccessory button is not shown

I try to manage annotations, and to display an info button on the right of the view when a PIN get selected, my relevant code is this:
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *newAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"greenPin"];
if ([annotation isKindOfClass:[ManageAnnotations class]]) {
static NSString* identifier = #"ManageAnnotations";
MKPinAnnotationView *newAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
if (newAnnotation==nil) {
newAnnotation=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
}else {
newAnnotation.annotation=annotation;
}
newAnnotation.pinColor = MKPinAnnotationColorGreen;
newAnnotation.animatesDrop = YES;
newAnnotation.canShowCallout = YES;
newAnnotation.rightCalloutAccessoryView=[UIButton buttonWithType:UIButtonTypeInfoLight];
return newAnnotation;
}else {
newAnnotation.pinColor = MKPinAnnotationColorGreen;
newAnnotation.animatesDrop = YES;
newAnnotation.canShowCallout = YES;
return newAnnotation;
}
ManageAnnotations.m :
#implementation ManageAnnotations
#synthesize pinColor;
#synthesize storeName=_storeName;
#synthesize storeAdress=_storeAdress;
#synthesize coordinate=_coordinate;
-(id)initWithTitle:(NSString*)storeName adress:(NSString*)storeAdress coordinate:(CLLocationCoordinate2D)coordinate{
if((self=[super init])){
_storeName=[storeName copy];
_storeAdress=[storeAdress copy];
_coordinate=coordinate;
}
return self;
}
-(NSString*)title{
return _storeName;
}
-(NSString*)subtitle{
return _storeAdress;
}
ManageAnnotations.h
#interface ManageAnnotations : NSObject<MKAnnotation>{
NSString *_storeName;
NSString *_storeAdress;
CLLocationCoordinate2D _coordinate;
}
//
#property(nonatomic,assign)MKPinAnnotationColor pinColor;
#property(nonatomic, readonly, copy)NSString *storeName;
#property(nonatomic, readonly, copy)NSString *storeAdress;
#property(nonatomic,readonly)CLLocationCoordinate2D coordinate;
//
-(id)initWithTitle:(NSString*)storeName adress:(NSString*)storeAdress coordinate:(CLLocationCoordinate2D)coordinate;
//
The PINS are shown correctly on the Map, but without the info button on the right of the view. Am i missing something?
Are you actually going into the condition? Set a breakpoint to check.
Why create a MKPinAnnotationView at the beginning, before you know the type of annotation?
You should dequeue your annotationView instead of alloc/initWithAnnotation:reuseIdentifier
When you reuse your annotations, you should put everything that doesn't change (color, animation, etc) after the alloc init, and not reset them all the time. Otherwise you lose the interest of reusing.
Other than that your code seems fine, and comparing it to mine, I don't see anything obvious. Remark 1 is the most probable. I would set a breakpoint to see if I really go there, see if I can show a leftCalloutAccessoryView instead, use a different pinColor.

How to display json image array in UITableView using multithreading?

I have few images on my server whose names are stored in the phpmysql table. The table contains two fields: id and images. I have prepared a php to fetch the images in json encoded formatted as mentioned:
jsonFetch.php
<?php
$dbhost = "localhost";
$dbname = "userauth";
$dbuser = "root";
//$DB_Pass = "root";
$dbtable = "images";
#mysql_connect($dbhost, $dbuser);
$db = mysql_select_db($dbname);
$sql = "SELECT * FROM $dbtable";
$query = mysql_query($sql);
while($row = mysql_fetch_array($query))
{
$rows[] = array(
//"id" => $row[0],
"image" => $row[1]
//"description" => $row['description']);
);
}
$json = json_encode($rows);
$callback = $_GET['images'];
echo $callback.$json ;
//print_r($json);
?>
Now, when i hit the url, i am getting following response:
[{"image":"./95462"},{"image":"./8838upload_image.jpg"}{"image":"./43185upload_image.jpg"},{"image":"/17426upload_image.jpg"}]
I am getting json array as above.
The next step is to display the above array in multithreaded manner in UITableView.
I am getting the images from url when i hardcode them but when it comes to json parse, i am a noob. I have tried every possible manner in which json can be parsed so for you reference, i am posting the .m file. :
#import "json.h"
#interface profilePhotos(Private)
- (void) initialize;
- (void) loadImage:(id)arg;
- (void) updateTableView:(id)arg;
- (void) addImagesToQueue:(NSArray *)images;
- (void) addImagesToQueue:(NSArray *)arrayImages;
- (void) addImagesToQueue:(NSArray *)arrayDataFromServer;
- (void) showcommentView;
- (void) hidecommentView;
#end
#implementation profilePhotos
#synthesize photosTable;
#synthesize addPhotos;
#synthesize deletePhotos;
#synthesize back;
#synthesize imageQueue, loadedImages, imageLoaderOpQueue, commentView;
//#synthesize photosView;
-(void)initializeWith:(int)buttonTag{
tag = buttonTag;
NSLog(#"tag = %d", tag);
}
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (!(self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
return self;
}
[self initialize];
return self;
}
- (void) awakeFromNib
{
NSLog(#"AsyncImageLoadingViewController::awakeFromNib called");
[super awakeFromNib];
[self initialize];
}
- (void) viewDidLoad
{
NSLog(#"AsyncImageLoadingViewController::viewDidLoad called");
[super viewDidLoad];
}
- (void) viewDidAppear:(BOOL)animated
{
NSLog(#"AsyncImageLoadingViewController::viewDidAppear called");
[super viewDidAppear:animated];
NSArray *images = [NSArray arrayWithObjects:
#"http://dl.dropbox.com/u/9234555/avatars/ava01.gif",
#"http://dl.dropbox.com/u/9234555/avatars/ava02.gif",
#"http://dl.dropbox.com/u/9234555/avatars/ava03.gif",
#"http://dl.dropbox.com/u/9234555/avatars/ava04.gif",
#"http://dl.dropbox.com/u/9234555/avatars/ava05.gif", nil];
[self addImagesToQueue:images];
NSLog(#"addImagesToQueue: %#",self);
}
#pragma mark -
#pragma mark Private Methods
/*!
#method
#abstract initializes class variables
*/
- (void) initialize
{
NSLog(#"AsyncImageLoadingViewController::initialize called");
NSMutableArray *a = [[NSMutableArray alloc] init];
self.imageQueue = a;
//[a release];
a = [[NSMutableArray alloc] init];
self.loadedImages = a;
//[a release];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
self.imageLoaderOpQueue = queue;
//[queue release];
}
/*!
#method
#abstract updates tableview for the newly downloaded image and scrolls the tableview to bottom
*/
- (void) updateTableView:(id)arg
{
NSLog(#"AsyncImageLoadingViewController::updateTableView called");
if ((arg == nil) || ([arg isKindOfClass:[UIImage class]] == NO)) {
return;
}
// store the newly downloaded image
[self.loadedImages addObject:arg];
//[arg release];
// refresh tableview
[self.photosTable reloadData];
// scroll to the last cell of the tableview
NSIndexPath *lastRow = [NSIndexPath indexPathForRow:([self.loadedImages count] - 1) inSection:0];
[self.photosTable scrollToRowAtIndexPath:lastRow
atScrollPosition:UITableViewScrollPositionBottom
animated:YES];
}
/*!
#method
#abstract downloads images, this is the method that dispatches tasks in the operation q ueue
*/
- (void) loadImage:(id)arg
{
NSLog(#"AsyncImageLoadingViewController::loadImage called");
if ((arg == nil) || ([arg isKindOfClass:[NSString class]] == NO)) {
return;
}
// create a local autorelease pool since this code runs not on main thread
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// fetch the image
NSLog(#"AsyncImageLoadingViewController::loadImage - will download image: %#", arg);
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:arg]];
UIImage *image = [UIImage imageWithData:data];
NSLog(#"image: %#",image);
// update tableview with the downloaded image on main thread
[self performSelectorOnMainThread:#selector(updateTableView:) withObject:image waitUntilDone:NO];
//[pool release];
}
/*!
#method
#abstract adds images to the queue and starts the operation queue to download them
*/
- (void) addImagesToQueue:(NSArray *)images
{
NSLog(#"AsyncImageLoadingViewController::addImagesToQueue called");
[self.imageQueue addObjectsFromArray:images];
NSLog(#"addImagesToQueue Array: %#", self);
// suspend the operation queue
[self.imageLoaderOpQueue setSuspended:YES];
// add tasks to the operation queue
for (NSString *imageUrl in self.imageQueue) {
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(loadImage:) object:imageUrl];
[self.imageLoaderOpQueue addOperation:op];
// [op release];
}
// clear items in the queue and resume the operation queue to start downloading images
[self.imageQueue removeAllObjects];
[self.imageLoaderOpQueue setSuspended:NO];
}
#pragma mark -
#pragma mark UITableViewDataSource Methods
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.loadedImages count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
//cell = [[[UITableViewCell alloc] initWithStyle:UITableViewStyleGrouped reuseIdentifier:CellIdentifier] autorelease];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewStyleGrouped reuseIdentifier:[NSString stringWithFormat:#"cellID%d",indexPath.row]];
cell.accessoryType =UITableViewCellAccessoryNone;
//cell.accessoryType =UITableViewCellAccessoryDisclosureIndicator;
}
for(UIView *subviews in cell.subviews)
[subviews removeFromSuperview];
UIImageView *photo;
photo=[[UIImageView alloc] init];
[photo setImage:[self.loadedImages objectAtIndex:indexPath.row]];
[photo setFrame:CGRectMake(0, 5, 150, 120)];
[cell addSubview:photo];
return cell;
}
-(void)aMethod:(UIButton *)sender{
//[sender tag];
NSIndexPath *indexPath = [photosTable indexPathForCell: (UITableViewCell*)[[sender superview]superview]];
NSLog(#"[sender tag] is %d",[sender tag]);
if([sender tag]==indexPath.row){
textField = (UITextField*)[cell viewWithTag:[sender tag]];
textField.hidden=NO;
}
//}
}
#pragma mark -
#pragma mark UITableViewDelegate Methods
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload{
// [self setPhotosView:nil];
[self setPhotosTable:nil];
[self setAddPhotos:nil];
[self setDeletePhotos:nil];
[self setBack:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:( UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
I believe that something is needed to be done in viewDidAppear method but what is it i don't understand.
Kindly, help me out. I have tried every possible json method . May be i am making some errors in that but i am all the way frustrated. Please help me please.
Dude..use following reference and you will get tutorial as working demo..
images in UITableView using multithreading
See this reference if you are new in iOS. It's simple
Hope, this will help you...
i suggest you to use SDWebImage
Web Image
This library provides a category for UIImageVIew with support for remote images coming from the web.
It provides:
An UIImageView category adding web image and cache management to the Cocoa Touch framework
An asynchronous image downloader
An asynchronous memory + disk image caching with automatic cache expiration handling
A guarantee that the same URL won't be downloaded several times
A guarantee that bogus URLs won't be retried again and again
Performances!
Try it - https://github.com/rs/SDWebImage

Getting xml data in DetailView from a map view (Iphone IOS)

We are trying to create a mapview with annotations loaded from a xml file. This works so far, and is making use of the KMLViewer code on the apple developer library. Now we are trying to load the data from the XML file into the detailview but only the corresponding entry. So when you click on details on a city for instance, details must be loaded from the xml file of that city.
We are trying for days now but just don't know where to start. We have the following code now:
detailviewcontroller.m
#import "DetailViewController.h"
#implementation DetailViewController
#synthesize address;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib
- (void)viewDidLoad
{
TabbedCalculationAppDelegate *appDelegate = (TabbedCalculationAppDelegate *)[[UIApplication sharedApplication] delegate];
address.text = appDelegate.addressInput1 ;
[super viewDidLoad];
}
- (void)viewDidUnload
{
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc
{
[super dealloc];
}
Map view
#import "locator.h"
#import "DetailViewController.h"
#implementation locator
#synthesize map, detailViewController, rightButton, customPinView;
- (void)viewDidLoad
{
[super viewDidLoad];
// create a custom navigation bar button and set it to always says "Back"
UIBarButtonItem *temporaryBarButtonItem = [[UIBarButtonItem alloc] init];
temporaryBarButtonItem.title = #"Back";
self.navigationItem.backBarButtonItem = temporaryBarButtonItem;
[temporaryBarButtonItem release];
// Locate the path to the route.kml file in the application's bundle
// and parse it with the KMLParser.
NSString *path = [[NSBundle mainBundle] pathForResource:#"branches" ofType:#"kml"];
kml = [[KMLParser parseKMLAtPath:path] retain];
// Add all of the MKOverlay objects parsed from the KML file to the map.
NSArray *overlays = [kml overlays];
[map addOverlays:overlays];
// Add all of the MKAnnotation objects parsed from the KML file to the map.
NSArray *annotations = [kml points];
[map addAnnotations:annotations];
// Walk the list of overlays and annotations and create a MKMapRect that
// bounds all of them and store it into flyTo.
MKMapRect flyTo = MKMapRectNull;
for (id <MKOverlay> overlay in overlays) {
if (MKMapRectIsNull(flyTo)) {
flyTo = [overlay boundingMapRect];
} else {
flyTo = MKMapRectUnion(flyTo, [overlay boundingMapRect]);
}
}
for (id <MKAnnotation> annotation in annotations) {
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
if (MKMapRectIsNull(flyTo)) {
flyTo = pointRect;
} else {
flyTo = MKMapRectUnion(flyTo, pointRect);
}
}
// Position the map so that all overlays and annotations are visible on screen.
MKCoordinateRegion mapRegion;
mapRegion.center.latitude = 51.522416;
mapRegion.center.longitude = 5.141602;
mapRegion.span.latitudeDelta = 5;
mapRegion.span.longitudeDelta = 5;
[map setRegion:mapRegion animated:YES];
}
#pragma mark MKMapViewDelegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
return [kml viewForOverlay:overlay];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// handle custom annotations
// // try to dequeue an existing pin view first
static NSString* BridgeAnnotationIdentifier = #"bridgeAnnotationIdentifier";
MKPinAnnotationView* pinView = (MKPinAnnotationView *)
[map dequeueReusableAnnotationViewWithIdentifier:BridgeAnnotationIdentifier];
if (!pinView)
{
// if an existing pin view was not available, create one
customPinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:BridgeAnnotationIdentifier] autorelease];
customPinView.pinColor = MKPinAnnotationColorPurple;
customPinView.animatesDrop = YES;
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;
//
rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}else{
return pinView;}
return nil;
}
#pragma mark -
#pragma mark MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
{
if (view.annotation == mapView.userLocation)
return;
rightButton = (DetailViewController *)view.annotation;
//show detail view using buttonDetail...
}
// the detail view does not want a toolbar so hide it
[self.navigationController setToolbarHidden:YES animated:YES];
[self.navigationController pushViewController:self.detailViewController animated:YES];
}
- (void)viewDidUnload
{
self.detailViewController = nil;
}
- (void)dealloc
{
[detailViewController release];
[super dealloc];
}
#end
As you can see the code is starting to look messy after trying tons of stuff, but we don't really know where to start.
Any help would be extremely appreciated
Thnx in advance!
Please have a look at the interface of the KMLPlacemark in KMLParser, there you can see what is exactly parsed and stored of an xml placemark element. For example the address is missing. So you will have to add all the information you want the parser to gather by implementing the fields in the KMLPlacemark class and alter the KMLParser methods:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName ...
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName ...
as well as some parts of the KMLPlacemark implementation. To fill the new fields with the parser you'll have to write methods like the - (void)beginName and - (void)endName. It will get a bit tricky when the elements you want to parse have children.
It could be helpful to split the KMLParser file into several files which contain one class each.
If you have achieved that and your placemark contains all the needed details you can catch the tap on an annotation with the MKMapViewDelegate protocol. Implement didDeselectAnnotationView, which could look like this:
- (void) mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
// implementation example of placemarkForAnnotation below
KMLPlacemark * placemark = [kml placemarkForAnnotation:view.annotation];
MyDetailViewController * myDetailViewController = [[MyDetailViewController alloc] initWithPlacemark:placemark];
[self presentModalViewController:myDetailViewController animated:YES];
[myDetailViewController release];
}
In KMLParser add
- (KMLPlacemark *)placemarkForAnnotation:(id <MKAnnotation>)point
{
// Find the KMLPlacemark object that owns this point and return it
for (KMLPlacemark *placemark in _placemarks) {
if ([placemark point] == point)
return placemark;
}
return nil;
}
Hope I could point you in the right direction. It'll be some work ;)

Display annotation in Map kit

I am working with Mapkit and I have to show annotations in the map but I'm not able to display the annotation. Here's my code:
#interface MyMapView : UIViewController <MKAnnotation,MKMapViewDelegate>{
MKMapView *Obj_Map_View;
MKPlacemark *pmark;
MKReverseGeocoder *geocoder1;
}
#end
#import "MyMapView.h"
#implementation MyMapView
- (id)init {
if (self = [super init]) {
}
return self;
}
- (void)loadView {
[super loadView];
Obj_Map_View = [[MKMapView alloc]initWithFrame:self.view.bounds];
Obj_Map_View.showsUserLocation =YES;
Obj_Map_View.mapType=MKMapTypeStandard;
[self.view addSubview:Obj_Map_View];
Obj_Map_View.delegate = self;
CLLocationCoordinate2D cord = {latitude: 19.120000, longitude: 73.020000};
MKCoordinateSpan span = {latitudeDelta:0.3, longitudeDelta:0.3};
MKCoordinateRegion reg= {cord,span};
[Obj_Map_View setRegion:reg animated:YES];
//[Obj_Map_View release];
}
- (NSString *)subtitle{
return #"Sub Title";
}
- (NSString *)title{
return #"Title";
}
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
MKPinAnnotationView *annov = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"Current location"];
annov.animatesDrop = TRUE;
[annotation title]==#"Current location";
annov.canShowCallout = YES;
[annov setPinColor:MKPinAnnotationColorGreen];
return annov;
}
The above code works fine and displays a map but not with annotation.
Typically, the class that conforms to the MKAnnotation protocol isn't the view controller, it's a data class.
You'll need to create another class, which I'll call "MyLandmarks" for the example.
#interface MyLandmarks : NSObject <MKAnnotation>
// Normally, there'd be some variables that contain the name and location.
// And maybe some means to populate them from a URL or a database.
// This example hard codes everything.
#end
#implementation MyLandmarks
-(NSString*)title {
return #"'ere I am, J.H.";
}
-(NSString*)subtitle {
return #"The ghost in the machine.";
}
-(CLLocationCoordinate2D) coordinate {
CLLocationCoordinate2D coord = {latitude: 19.120000, longitude: 73.020000};
return coord;
}
#end
Then, somewhere appropriate in your MyMapView class add:
MyLandmark *landmark = [[[MyLandmark alloc]init]autorelease];
[Obj_Map_View addAnnotation:landmark];
A couple other bits that other Objective-C developers working with you will appreciate:
To avoid confusion, don't call the class MyMapView if it descends from a UIViewController. Call it MyMapViewController, instead.
Classes start with a capital letter, variables start lowercase. Both are CamelCased. Obj_Map_View should be objMapView.
To add annotation use : addAnnotation:
read about it here