Show MapPin title on user tap - ios

I have made a MapPin class like this
//.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapPin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
AND
.m
#import "MapPin.h"
#implementation MapPin
#synthesize coordinate,title,subtitle;
#end
And then in the cellForRowAtIndexPath of my class, I have
MapPin *ann = [[MapPin alloc] init];
ann.title = #"HERE";
ann.subtitle = #"Test";
ann.coordinate = region.center;
[riCell.mapView addAnnotation:ann];
And when the user taps on it I want the title and subtitle to show? Is there a method like on MapPin tap? I though it was supposed to occur automoactilly?
How can I show it on the user tap?
Thanks

You can use CLGeocoder delegate method and use CLPlacemark object and get the locality and distribute to the annotation accordingly
// get the place details from the current location
[geocoder reverseGeocodeLocation:self.locationManager.location
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error){
NSLog(#"Geocode failed with error: %#", error);
return;
}
// get all the details of the current location
placemark = [placemarks objectAtIndex:0];
// set the place details to the annotation
annotation.title = [NSString stringWithString:_placemark.subLocality];
annotation.subtitle = [NSString stringWithString:_placemark.locality];
[self.mapView addAnnotation:annot];
}];
}

This is Swift code ... same you need to implement in Objective C
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
/*
For now, all we have are some quick and dirty pins for viewing debug
annotations. To learn more about showing annotations,
see "Annotating Maps".
*/
if (annotation.title! == "red") {
let pinView = MKPinAnnotationView()
if #available(iOS 9.0, *) {
pinView.pinTintColor = UIColor.redColor()
} else {
pinView.pinColor = MKPinAnnotationColor.Red
}
pinView.canShowCallout = true
pinView.draggable = true
return pinView
}
canShowCallout = true is the Key here

Related

Custom MKAnnotationView Showing Wrong Image

I have an MKMapView where I want to display annotations of contacts' faces. I looked at Apple's sample app MapCallouts and have so far written this:
Annotation.h
#interface Annotation : NSObject <MKAnnotation>
#property (nonatomic, strong) UIImage *image;
#property (nonatomic, readwrite) CLLocationCoordinate2D coordinate;
+ (MKAnnotationView *)createViewAnnotationForMapView:(MKMapView *)mapView annotation:(id <MKAnnotation>)annotation;
#end
Annotation.m
#import "CustomAnnotationView.h"
#implementation Annotation
+ (MKAnnotationView *)createViewAnnotationForMapView:(MKMapView *)mapView annotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *returnedAnnotationView =
(CustomAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"Annotation"];
if (returnedAnnotationView == nil)
{
returnedAnnotationView =
[[CustomAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"Annotation"];
}
return returnedAnnotationView;
}
#end
CustomAnnotationView.h
#interface CustomAnnotationView : MKAnnotationView
CustomAnnotationView.m
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithAnnotation:annotation reuseIdentifier:#"Annotation"];
if (self != nil)
{
Annotation *mapItem = (Annotation *)self.annotation;
// Create imageView and labels, etc.
}
return self;
}
Then, to drop my annotation, I have this method which loops through an array of contacts, gets their address, finds the CLLOcationCoordinate2D, and creates an Annotation.
-(void)sortContacts{
for (APContact *contact in self.peopleArray){
[operationQueue addOperationWithBlock:^{
NSString *addressString = // get address from contact;
contact.addressString = addressString;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:addressString
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0 && !error) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
CLLocation *location = topResult.location;
CLLocationCoordinate2D coordinate = location.coordinate;
Annotation *annotation = [[Annotation alloc] init];
annotation.image = [UIImage imageNamed:#"Annotation"];
if (contact.thumbnail.size.width > 0){
annotation.image = contact.thumbnail;
}
else{
annotation.image = [UIImage imageNamed:#"Annotation"];
}
annotation.coordinate = coordinate;
[self.mapView addAnnotation:annotation];
}
else if (error){
NSLog(#"ERROR");
}
}
];
}];
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
CustomAnnotationView *returnedAnnotationView = nil;
if ([annotation isKindOfClass:[Annotation class]])
{
returnedAnnotationView = (CustomAnnotationView *)[Annotation createViewAnnotationForMapView:self.mapView annotation:annotation];
}
return returnedAnnotationView;
}
However, when I scroll across self.mapView, the incorrect contact images are showing for the wrong annotations. I'm not sure how to fix this. Any help would be much appreciated. Thanks
I added a property to my custom annotation view and simply changed the image everytime I dequeued or created a new annotation.
#property (nonatomic, strong) UIImageView *annotationImage;

override MKPointAnnotation class [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I override MKAnnotation and add two property (NSManagedObject and UIImage) to MKAnnotation class something like that but it's not work what is wrong with this code?
// myAnnotation.h
#import <MapKit/MapKit.h>
#interface myAnnotation : NSObject<MKAnnotation>{
NSManagedObject *Contact;
UIImage *image;
NSString *title;
NSString *subtitle;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic,copy) NSManagedObject *Contact;
#property (nonatomic, copy) UIImage *image;
#property (nonatomic,assign) CLLocationCoordinate2D coordinate;
#property (nonatomic,copy) NSString *title;
#property (nonatomic,copy) NSString *subtitle;
#end
// myAnnotation.m
#import "myAnnotation.h"
#implementation myAnnotation
#synthesize Contact,title,subtitle,coordinate,image;
#end
// MapVC.h
#import "myAnnotation.h"
#interface MapVC : UIViewController<MKMapViewDelegate,UIActionSheetDelegate,MFMessageComposeViewControllerDelegate,MFMailComposeViewControllerDelegate,UISearchBarDelegate>{
MKMapView *mapview;
myAnnotation *tmpContact;
}
// MapVC.m
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[mapview removeAnnotations:mapview.annotations];
//add each object in Contacts entity to map view
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
fetchRequest=[[NSFetchRequest alloc]initWithEntityName:#"Contacts"];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)]];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];
for (NSManagedObject *info in fetchedObjects) {
NSLog(#"Name: %#", [info valueForKey:#"name"]);
//initializetion latitude and longitude
aLng=[[info valueForKey:#"lng"] doubleValue];
aLat=[[info valueForKey:#"lat"] doubleValue];
//if latitude and longitude not null
if(aLng && aLat && aLng!=0.0 &&aLat!=0.0)
{
//create a new Coordinate
CLLocationCoordinate2D wimLocation;
wimLocation.latitude=aLat;
wimLocation.longitude=aLng;
myAnnotation *myAnn=[myAnnotation alloc];
myAnn.coordinate=wimLocation;
myAnn.title=[info valueForKey:#"name"];
myAnn.Contact=info;
UIImage *image = [UIImage imageWithData:[info valueForKey:#"photo"]];
myAnn.image=image;
//add create Annotation to mapview
[self.mapview addAnnotation:myAnn];
}
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[myAnnotation class]])
{
static NSString *reuseId = #"ann";
MKAnnotationView *av = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (av == nil)
{
av = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
}
else
{
av.annotation = annotation;
}
myAnnotation *ann = (myAnnotation *)annotation;
av.image = ann.image;
return av;
}
//return nil (default view) if annotation is not our custom type
return nil;
}
Just subclass MKPointAnnotation or implement the MKAnnotation protocol in your custom class.

MKAnnotation not displaying on map view

I am trying to create a custom annotation for a simple map view of mine, but the annotaiton pin is not showing up on the map when i run the simulator.
I have a MapViewAnnotation class which implements the MKAnnotation protocol, and I have another MapViewController class where I programmatically create a mapView and display the map.
MapViewAnnotation.h :
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapViewAnnotation : NSObject <MKAnnotation>
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
-(id) initWithTitle: (NSString *) title AndCoordinate: (CLLocationCoordinate2D) coordinate;
#end
MapViewAnnotation.m :
#import "MapViewAnnotation.h"
#implementation MapViewAnnotation
#synthesize coordinate = _coordinate;
#synthesize title = _title;
-(id) initWithTitle:(NSString *)title AndCoordinate:(CLLocationCoordinate2D)coordinate{
self = [super init];
_title = title;
_coordinate = coordinate;
return self;
}
#end
MapViewController.h :
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController
#property (weak, nonatomic) MKMapView *mapView;
-(void) goToLocation;
#end
MapViewController.m :
#import "MapViewController.h"
#import "MapViewAnnotation.h"
#define LATITUDE 42.3889;
#define LONGITUDE -72.5278;
#interface MapViewController ()
#end
#implementation MapViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView = [[MKMapView alloc] initWithFrame:self.view.frame];
[self.view addSubview:self.mapView];
[self goToLocation];
[self.mapView addAnnotations:[self createAnnotations]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void) goToLocation {
MKCoordinateRegion newRegion;
newRegion.center.latitude = LATITUDE;
newRegion.center.longitude = LONGITUDE;
newRegion.span.latitudeDelta = 0.05f;
newRegion.span.longitudeDelta = 0.05f;
self.mapView.showsPointsOfInterest = YES;
[self.mapView setRegion:newRegion animated:YES];
}
-(NSMutableArray *) createAnnotations {
NSMutableArray *annotations = [[NSMutableArray alloc] init];
NSString *path = [[NSBundle mainBundle] pathForResource:#"location" ofType:#"plist"];
NSArray *locations = [NSArray arrayWithContentsOfFile:path];
for (NSDictionary *row in locations){
NSNumber *latitude = [row objectForKey:#"latitude"];
NSNumber *longitude = [row objectForKey:#"longitude"];
NSString *title = [row objectForKey:#"title"];
CLLocationCoordinate2D coord;
coord.latitude = latitude.doubleValue;
coord.longitude = longitude.doubleValue;
MapViewAnnotation *annotation = [[MapViewAnnotation alloc] initWithTitle:title AndCoordinate:coord];
[annotations addObject: annotation];
}
return annotations;
}
#end
I am taking am going through a plist where I have coordinates for one test location that I am trying to show on my map, but the pin is not displaying on the map. Again, I am doing this all programmatically, no xib, or storyboards (although that should not be the problem).
I do not know why the annotation is not showing up. I tried looking on stack for some other situations like mine but was unlucky to find anything that could help.
Thank you.
Answer was pretty simple,
In my plist I had the coordinates
latitude: 42.37
longitude: 72.536
when it should of actually been -72.536 for longitude.

iOS 7 Reverse Geocoding Using Mapkit

I am making an app with a map that shows the location that you type in a text field, also if you move around the map it displays on the text field the address of the location that you are looking at.
When I move around the map it display the address in the text field and shows only the street, but I was wondering if it is possible to show the address as is used in Colombia, for example: Carrera 1 # 18A - 12.If you type the address like the example in the text field it works and it founds it in the map, but does not display the address in the text field as I want.
Here is the code I am using.
If somebody can help me i would really appreciate it.
Thanks
.h file
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface ViewControllerMapaDestinoCasa : UIViewController < UITextFieldDelegate, MKMapViewDelegate>
#property (strong, nonatomic) CLLocation *ubicacionSeleccionada;
#property (strong, nonatomic) NSMutableDictionary *lugarDiccionario;
#property (strong, nonatomic) IBOutlet MKMapView *mapa;
#property (strong, nonatomic) IBOutlet UITextField *textFieldDireccion;
- (IBAction)botonUbicacionActual:(id)sender;
#end
.m file
#import "ViewControllerMapaDestinoCasa.h"
#interface ViewControllerMapaDestinoCasa ()
#end
#implementation ViewControllerMapaDestinoCasa
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.textFieldDireccion.delegate = self;
self.mapa.delegate = self;
self.lugarDiccionario = [[NSMutableDictionary alloc] init];
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 4.609886;
zoomLocation.longitude= -74.08205;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 1609.344,1609.344);
[self.mapa setRegion:viewRegion animated:YES];
}
- (IBAction)botonUbicacionActual:(id)sender {
[self updatePlaceDictionary];
[self updateMaps];
}
- (void)updatePlaceDictionary {
[self.lugarDiccionario setValue:self.textFieldDireccion.text forKey:#"Street"];
[self.lugarDiccionario setValue:#"Bogotá" forKey:#"City"];
[self.lugarDiccionario setObject:#"Colombia" forKey:#"Country"];
}
- (void)updateMaps {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressDictionary:self.lugarDiccionario completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
[self.mapa setCenterCoordinate:coordinate animated:YES];
} else {
NSLog(#"error");
}
}];
}
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
self.ubicacionSeleccionada =
[[CLLocation alloc] initWithLatitude:mapView.centerCoordinate.latitude
longitude:mapView.centerCoordinate.longitude];
[self performSelector:#selector(delayedReverseGeocodeLocation)
withObject:nil
afterDelay:0.3];
}
- (void)delayedReverseGeocodeLocation {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self reverseGeocodeLocation];
}
- (void)reverseGeocodeLocation {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:self.ubicacionSeleccionada completionHandler:^(NSArray *placemarks, NSError *error) {
if(placemarks.count){
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
[self.textFieldDireccion setText:[dictionary valueForKey:#"Street"]];
}
}];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
#end
Here is the code I use to get the full address, if I understood your question correctly.
[geocoder reverseGeocodeLocation:touchLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (!error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
// Update annotation with address
self.person.address.state = placemark.administrativeArea;
self.person.address.city = placemark.locality;
NSString *placemarkAddress;
//Accounts for the possibility of the number or street being null
if (placemark.subThoroughfare && placemark.thoroughfare){
placemarkAddress = [NSString stringWithFormat:#"%# %#",placemark.subThoroughfare, placemark.thoroughfare];
}
else if (placemark.thoroughfare){
placemarkAddress = placemark.thoroughfare;
}
self.person.address.street1 = placemarkAddress;
self.person.address.zip = placemark.postalCode;
}
else {
//Error
}
}];

Gettin Bad Access while adding Annotations

I´m trying to to add many Annotations (depends on how many objects a have in my Array) to my Mapview like this:
-(void)viewWillAppear:(BOOL)animated
{
[mapView removeAnnotations:mapView.annotations];
for (Daten *info in datenArray) {
CLLocationCoordinate2D location;
location.latitude = (double)[info.lati doubleValue];
location.longitude = (double)[info.longi doubleValue];
MapPin *newAnnotation =[[[MapPin alloc] initWithTitle:info.rating andCoordinate:location] autorelease];
[mapView addAnnotation:newAnnotation];
}
[self zoomToFitMapAnnotations:self.mapView];
[self.mapView selectAnnotation:self.mapView.annotations.lastObject animated:YES];
}
The first time I switch to that View it works perfectly...But if i come a second time to this View, i get this Bad Access with Error:
*** -[CFString length]: message sent to deallocated instance 0x17e140c0
Edit:
Thats my MapPin Class:
#interface MapPin : NSObject <MKAnnotation> {
NSString *title;
NSString *subtitle;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly, copy) NSString *subtitle;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d;
EDIT2:
Edit3:
Here´s the implementation:
#import "MapPin.h"
#implementation MapPin
#synthesize title, coordinate, subtitle;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d {
[super init];
subtitle = ttl;
title = #"Rating:";
coordinate = c2d;
return self;
}
- (void)dealloc {
[title release];
[subtitle release];
[super dealloc];
}
#end
You should send retain or copy message for object in init.
if (self = [super init]) {
subtitle = [ttl copy];
title = [#"Rating:" retain]
...
}
return self;
#"Rating:" is equal method which create autoreleased object.
Or you can use self.title = #"Rating:";.

Resources