How to display route beteen two latitude and longitude with custom name? - iphone

I have implemented one dating application in which I have open iPhone map application with source and destination latitude and longitude.But when i touch on the drop pin it display unkown road.But I want to display like user1 and user2 on drop pin.
Please help me for this query
Thanks in advance.

In your View Controller in which you're implementing MapView, you must be implementing MapView's delegate method, viewForAnnotation!!!
Implement it like this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
MKAnnotationView * annotationView = nil;
[mapLoadingIndicatorView stopAnimating];
if ([annotation isKindOfClass:[MKUserLocation class]]) {
[self.mapView.userLocation setTitle:#"User1"];
return annotationView;
}
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"currentAnnotation"];
annotationView.canShowCallout = YES;
return annotationView;
}
And also make sure you've made an AddressAnnotation Class in which
AddressAnnotation.h
#interface AddressAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString * title_;
NSString * subtitle_;
}
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString * title_;
#property (nonatomic, retain) NSString * subtitle_;
#end
And AddressAnnotation.m:
#implementation AddressAnnotation
#synthesize coordinate, title_, subtitle_;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c: (NSString *)title: (NSString *)subtitle {
if ((self = [super init])) {
coordinate= c ;
self.title_ = [NSString stringWithFormat:#"%#", title];
self.subtitle_ = [NSString stringWithFormat:#"%#", subtitle];
NSLog(#"title_%#", self.title_);
NSLog(#"subtitle_%#", self.subtitle_);
//self.title_ = #"Title";
//self.subtitle_ = #"Subtitle";
}
return self;
}
- (NSString *)title {
return self.title_;
}
- (NSString *)subtitle {
return self.subtitle_;
}
#end

Related

How to extend MKPointAnnotation and add a property to it

I'm trying to extend MKPointAnnotation and add a property to for an NSString called dealLink.
I thought I set it up correctly, but I'm getting this error at the moment:
Property 'dealLink' not found on object of type 'MKPointAnnotation *'
Here's my code in a view controller called MapOffersViewController.m:
#pragma mark - Populate Map
- (void)populateMap:(MKMapView*)map withDeals:(NSArray*) deals
{
NSLog(#"Deals " );
for (NSDictionary *currentDeal in deals) {
CLLocationCoordinate2D ctrpoint;
ctrpoint.latitude = [[[currentDeal objectForKey:#"coords"] objectForKey:#"lat"] doubleValue];
ctrpoint.longitude =[[[currentDeal objectForKey:#"coords"] objectForKey:#"lng"] doubleValue];
MKPointAnnotation *dealAnnotation = [[MKPointAnnotation alloc] init];
dealAnnotation.coordinate = ctrpoint;
dealAnnotation.title = [currentDeal objectForKey:#"vendor"];
**dealAnnotation.dealLink = [currentDeal objectForKey:#"link"];**
NSDictionary *currDict = #{
#"EUR": #"€",
#"GBP": #"₤",
#"USD": #"$",
#"BRL": #"R$"
};
NSString *currName = [currentDeal objectForKey:#"currency"];
NSString *currency = [currDict objectForKey:currName];
dealAnnotation.subtitle = [NSString stringWithFormat:#"%#%i",currency,[[currentDeal objectForKey:#"price"] integerValue ]];
NSLog(#"current deal id is %#",[currentDeal objectForKey:#"id"]);
[map setDelegate:self];
[map addAnnotation:dealAnnotation];
}
}
I'm importing this class called MapAnnotation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapAnnotation : MKPointAnnotation
{
NSString *title;
NSString *subtitle;
NSString *dealLink;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, retain) NSString *dealLink;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithTitle:(NSString *)ttl subTitle:(NSString *)subttl dealLink:(NSString *)dealLnk andCoordinate:(CLLocationCoordinate2D)c2d;
#end
and it's .m:
#import "MapAnnotation.h"
#implementation MapAnnotation
#synthesize title,subtitle,dealLink,coordinate;
- (id)initWithTitle:(NSString *)ttl subTitle:(NSString *)subttl dealLink:(NSString *)dealLnk andCoordinate:(CLLocationCoordinate2D)c2d {
title = ttl;
subtitle = subttl;
dealLink = dealLnk;
coordinate = c2d;
return self;
}
#end
thanks for any help
I used Craig's answer below and this additional code to get this working:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
NSLog(#"callout tapped from del method %#", dealUrl);
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:dealUrl]];
}
- (void)mapView:(MKMapView *)mapView1 didSelectAnnotationView:(MKAnnotationView *)mapView2
{
MapAnnotation *annotation = mapView2.annotation;
NSString *temp = annotation.dealLink;
dealUrl = temp;
// NSLog(#"temp is %#", temp);
}
You're creating an MKPointAnnotation and trying to access dealLink, which is only on MapAnnotations. You need to create a MapAnnotation
....
ctrpoint.longitude =[[[currentDeal objectForKey:#"coords"] objectForKey:#"lng"] doubleValue];
MapAnnotation *dealAnnotation = [[MapAnnotation alloc] init];
dealAnnotation.coordinate = ctrpoint;
....

'MyAnnotation' may not respond to 'initWithDictionary:'

I keep getting this semantic issue with this code ('MyAnnotation' may not respond to 'initWithDictionary:'), im adding annotations to a map using a plist.
Even though it displays the pin and everything i want it to, i get an semantic issue and cant seem to solve the problem
if anyone could help that would be great thanks
heres the code, the problem is in the //BrewMapViewController.m the error is on this line
MyAnnotation *annotation = [[MyAnnotation alloc] initWithDictionary:breweryDict];
/*MyAnnotation.h*/
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSString *test;
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, copy) NSString *test;
#end
/*MyAnnotation.m*/
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize coordinate, title, subtitle, test;
- (id) initWithDictionary:(NSDictionary *) dict
{
self = [super init];
if (self != nil) {
coordinate.latitude = [[dict objectForKey:#"latitude"] doubleValue];
coordinate.longitude = [[dict objectForKey:#"longitude"] doubleValue];
self.title = [dict objectForKey:#"name"];
self.subtitle = [dict objectForKey:#"address"];
self.test = [dict objectForKey:#"test"];
}
return self;
}
#end
/*BrewMapViewController.h*/
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface BrewMapViewController : UIViewController <MKMapViewDelegate> {
IBOutlet MKMapView *map;
NSArray *breweries;
}
#end
/*BrewMapViewController.m*/
#import "BrewMapViewController.h"
#import "MyAnnotation.h"
#implementation BrewMapViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
breweries = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:#"test"
ofType:#"xml"]];
double minLat = [[breweries valueForKeyPath:#"#min.latitude"] doubleValue];
double maxLat = [[breweries valueForKeyPath:#"#max.latitude"] doubleValue];
double minLon = [[breweries valueForKeyPath:#"#min.longitude"] doubleValue];
double maxLon = [[breweries valueForKeyPath:#"#max.longitude"] doubleValue];
MKCoordinateRegion region;
region.center.latitude = (maxLat + minLat) / 2.0;
region.center.longitude = (maxLon + minLon) / 2.0;
region.span.latitudeDelta = (maxLat - minLat) * 1.05;
region.span.longitudeDelta = (maxLon - minLon) * 1.05;
map.region = region;
for (NSDictionary *breweryDict in breweries){
MyAnnotation *annotation = [[MyAnnotation alloc] initWithDictionary:breweryDict];
[map addAnnotation:annotation];
[annotation release];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if (map.userLocation == annotation){
return nil;
}
NSString *identifier = #"MY_IDENTIFIER";
MKAnnotationView *annotationView = [map dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil){
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier]
autorelease];
annotationView.image = [UIImage imageNamed:#"beer.png"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.leftCalloutAccessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"pretzel.png"]] autorelease];
}
return annotationView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"I've been tapped");
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)dealloc {
[breweries release];
[map release];
[super dealloc];
}
#end
You have to put the method signature for - (id) initWithDictionary:(NSDictionary *) dict into your header file in order to tell BrewMapViewController that the method exists:
/*MyAnnotation.h*/
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSString *test;
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, copy) NSString *test;
- (id) initWithDictionary:(NSDictionary *) dict;
#end

Set annotation's title as current address

I want to get the current location's address and set it to the annotation's title. But it didn't work. I think it's because of the block, but I don't know how to fix it. Any help will be appreciated. The most related code is as following:
WhereAmIAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface WhereAmIAnnotation : NSObject <MKAnnotation>
{
CLLocation *myLocation;
NSString *addr;
}
#property (nonatomic, retain) CLLocation *myLocation;
#property (nonatomic, copy) NSString *addr;
#end
WhereAmIAnnotation.m
#import "WhereAmIAnnotation.h"
#implementation WhereAmIAnnotation
#synthesize myLocation, addr;
- (CLLocationCoordinate2D)coordinate;
{
return self.myLocation.coordinate;
}
- (NSString *)title
{
return self.addr;
}
#end
MapViewController.m
- (IBAction)gotoCurrentLocation{
self.mapView.showsUserLocation = YES;//a bar button linked with this action
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocation *currentLocation = userLocation.location;
MKCoordinateRegion newRegion;
newRegion.center = currentLocation.coordinate;
newRegion.span.latitudeDelta = 0.02;
newRegion.span.longitudeDelta = 0.02;
[self.mapView setRegion:newRegion animated:YES];
WhereAmIAnnotation *whereAmIAnnotation = [[WhereAmIAnnotation alloc] init];
whereAmIAnnotation.myLocation = currentLocation;
whereAmIAnnotation.addr = [self addrAtLocation:currentLocation];
[self.mapView addAnnotation:whereAmIAnnotation];
self.mapView.showsUserLocation = NO;
}
- (NSString *)addrAtLocation:(CLLocation *)location{
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemark, NSError *error) {
CLPlacemark *topResult = [placemark objectAtIndex:0];
self.addr = [NSString stringWithFormat:#"%# %# %# %#", topResult.country, topResult.locality, topResult.subLocality, topResult.thoroughfare];
}];
return self.addr;
}
I should implement this method
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id )annotation{}
sorry for this stupid question!
You are returning the address while modifying it inside an asynchronous block. You should move the return inside the block, or a create a protocol to handle passing this information back to the caller.
Change the block to this:
- (void)addrAtLocation:(CLLocation *)location{
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemark, NSError *error) {
CLPlacemark *topResult = [placemark objectAtIndex:0];
whereAmIAnnotation.addr = [NSString stringWithFormat:#"%# %# %# %#", topResult.country, topResult.locality, topResult.subLocality, topResult.thoroughfare];
}];
}
Then make whereAmIAnnotation a member variable. Do you understand WHY this fixes your issues?
Create .h file
#interface MapPinClass : NSObject <MKAnnotation>{
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle,*color,*index,*locationId;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle,*color,*index,*locationId;
Create .m file
#implementation MapPinClass
#synthesize coordinate,title,subtitle,color,index,locationId;
-(void)dealloc{
[title release];
[super dealloc];
}
write a code where you set
MapPinClass *ann = [[MapPinClass alloc] init];
ann.title = AppMain.Heading;
ann.subtitle = AppMain.Detail;
ann.coordinate = region.center;
[myMapView addAnnotation:ann];
I should implement this method
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation{}
Sorry for that stupid question.

removing/adding annotations to mapview cause memory leaks

I've been trying to get rid of memory leaks in mapview. I am using custom map pin class.
Everything works, but problem is - I need to filter mapview results. when i remove all mapview annotations - and add filtered results - performance tool finds leaks. but in this mapPin class I am using are used autorelease, so they should be released, but they aren't. what am I doing wrong?
MapPin.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <MapKit/MKMapView.h>
#import <MapKit/MKAnnotation.h>
#interface MapPin : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString * picture;
NSInteger tag_number;
}
#property (nonatomic,assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord;
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord title:(NSString *) title;
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord title:(NSString *) title subtitle:(NSString *) subtitle;
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord title:(NSString *) title subtitle:(NSString *) subtitle image:(NSString *) pic;
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord title:(NSString *) title subtitle:(NSString *) subtitle image:(NSString *) pic num:(NSInteger) number;
- (void) setPic:(NSString *) picture;
- (NSString* ) getPic;
- (void) setNum:(NSInteger) tag_number;
- (NSInteger ) getNum;
#end
MapPin.m
#import "MapPin.h"
#implementation MapPin
#synthesize coordinate = _coordinate;
#synthesize title = _title;
#synthesize subtitle = _subtitle;
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord
{
return [self initWithCoordinate:coord title:#""];
}
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord title:(NSString *) title {
return [self initWithCoordinate:coord title:title subtitle:#""];
}
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord title:(NSString *) title subtitle:(NSString *) subtitle {
return [self initWithCoordinate:coord title:title subtitle:subtitle image:#""];}
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord title:(NSString *) title subtitle:(NSString *) subtitle image:(NSString *) pic{
MapPin * me = [[[MapPin alloc] init] autorelease];
me.coordinate = coord;
me.title = title;
me.subtitle = subtitle;
[me setPic:pic];
return me;
}
- (id) initWithCoordinate:(CLLocationCoordinate2D) coord title:(NSString *) title subtitle:(NSString *) subtitle image:(NSString *) pic num:(NSInteger) number{
MapPin * me = [[[MapPin alloc] init] autorelease];
me.coordinate = coord;
me.title = title;
me.subtitle = subtitle;
[me setPic:pic];
[me setNum:number];
return me;
}
- (void) setPic:(NSString*) pic {
picture = pic;
}
- (NSString * ) getPic{
return picture;
}
- (void) setNum:(NSInteger) number {
tag_number = number;
}
- (NSInteger ) getNum{
return tag_number;
}
#end
I have been using cutom map pin created by Mayur Birari, which i tweaked a little bit, to support custom map pin images and id's.
CustomMapPin.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface CustomMapPin : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString* title;
NSString* subtitle;
NSString* pic;
NSInteger tag_number;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString* title;
#property (nonatomic, copy) NSString* subtitle;
#property (nonatomic, copy) NSString* pic;
#property (nonatomic) NSInteger tag_number;
#end
CustomMapPin.m
#import "CustomMapPin.h"
#implementation CustomMapPin
#synthesize title;
#synthesize subtitle;
#synthesize coordinate;
#synthesize pic;
#synthesize tag_number;
- (void)dealloc
{
self.title = nil;
self.pic = nil;
self.subtitle = nil;
[super dealloc];
}
#end
and using it in class like this:
CLLocationCoordinate2D pinlocation;
in a loop I set up required values and create a map pin:
pinlocation.latitude = ...;
pinlocation.longitude = ...;
NSInteger pinID = ....;
CustomMapPin* customMapPin=[[CustomMapPin alloc] init];
customMapPin.coordinate=(CLLocationCoordinate2D
{pinlocation.latitude,pinlocation.longitude};
customMapPin.title=#"title";
customMapPin.subtitle=#"subtitle";
customMapPin.pic = #"customImageName";
customMapPin.tag_number = pinId;
[mapView addAnnotation:customMapPin];
Setting up custom image:
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
if ([annotation isKindOfClass: [CustomMapPin class]])
{
CustomMapPin * a = annotation;
[annView setImage:[UIImage imageNamed:a.pic]];
}
}
Getting pin id on callout:
- (void)mapView:(MKMapView *)mp annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
CustomMapPin * v = (CustomMapPin *) view.annotation;
int tagNumber = v.tag_number;
....
}
and finally - in my project It was required to have filter buttons - so I needed to remove all pins, and add required. By default calling mapview to remove all annotations created memory leaks. So when I need to clear mapview from annotations, I call this function:
- (void)removeAnnotations
{
NSMutableArray *toRemove = [NSMutableArray arrayWithCapacity:[mapView.annotations count]];
for (id annotation in mapView.annotations)
{
if (annotation != mapView.userLocation)
{
[toRemove addObject:annotation];
}
}
[mapView removeAnnotations:toRemove];
for(int i = 0; i < [toRemove count]; i++)
{
CustomMapPin * a = [toRemove objectAtIndex:i];
[a release];
a = nil;
}
}
Hope this helps
Happy coding! :)
You were just missing dealloc implementation!
for example:
- (void)dealloc
{
[self.title release];
self.title = nil;
self.subtitle release];
self.subtitle = nil;
[super dealloc];
}

Get variable and plug it into MKAnnotationView

I have code which i gives coordinates, title, subtitle, image file location information. This information is used to generate the annotation for a ios mapkit pin. The title and subtitle are automatically plugged in and i can grab the other info (image file location) after the pin is selected. I am looking to display a thumbnail of the image in the annotation (pin popup) however but i am having trouble setting it as a variable to get it from my info as opposed to hard coding it. Below is the code i use to generate my map/ pins.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
// Boilerplate pin annotation code
UIButton *detailButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
NSString *imageLoc;
MKPinAnnotationView *pin = (MKPinAnnotationView *) [self.map dequeueReusableAnnotationViewWithIdentifier: #"restMap"];
if (pin == nil) {
pin = [[[MKPinAnnotationView alloc] initWithAnnotation: annotation reuseIdentifier: #"restMap"] autorelease];
} else {
pin.annotation = annotation;
}
pin.pinColor = MKPinAnnotationColorRed;
pin.canShowCallout = YES;
pin.animatesDrop = YES;
NSString *imageLoc= ????????????
UIImageView *leftIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageLoc]];
pin.leftCalloutAccessoryView = leftIconView;
[detailButton addTarget:self action:#selector(showDetailView:) forControlEvents:UIControlEventTouchUpInside];
pin.rightCalloutAccessoryView = detailButton;
return pin;
}
#interface MapPin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *subtitle;
NSString *title;
NSString *indexnumber;
NSString *imageFile;
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly) NSString *title;
#property (nonatomic, readonly) NSString *subtitle;
#property (nonatomic, readonly) NSString *indexnumber;
#property (nonatomic, readonly) NSString *imageFile;
-(id)initWithCoordinates:(CLLocationCoordinate2D)location
placeName: placeName
description:description
indexnum:indexnum
imageFileLoc:imageFileLoc;
#end
#import "MapPin.h"
#implementation MapPin
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
#synthesize indexnumber;
#synthesize imageFile;
-(id)initWithCoordinates:(CLLocationCoordinate2D)location
placeName: placeName
description:description
indexnum:indexnum
imageFileLoc:imageFileLoc{
self = [super init];
if (self != nil) {
imageFile=imageFileLoc;
[imageFile retain];
indexnumber=indexnum;
[indexnumber retain];
coordinate = location;
title = placeName;
[title retain];
subtitle = description;
[subtitle retain];
}
return self;
}
What's available from the annotation object? Have you tried the following?
NSString *imageLoc = [annotation respondsToSelector:#selector(imageFile)] ? [annotation imageFile] : #"some_default_value";