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.
Related
I am developing an app in Xcode (objective-c). My app has a TableView with a list of restaurants and when you press one row, another view is opened with the restaurant information. The method I am using is that I am sending the title in the row to the new view and depending on the title I load the information of the restaurant. I want to do exactly the same using a map pin button. My problem is that I am trying to send the TitleLabel to other ViewController but this is not working and I don't know why.
This is my map pin: RestMapPin.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface RestMapPin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
This is my RestMappin.m:
#import "RestMapPin.h"
#implementation RestMapPin
#synthesize coordinate, title, subtitle;
#end
This is my MapViewController.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController {
MKMapView *mapView;
}
#property (weak, nonatomic) IBOutlet UIBarButtonItem *barButton;
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
-(IBAction)setMap:(id)sender;
#end
This is my MapViewController.m:
#import "MapViewController.h"
#import "SWRevealViewController.h"
#import "RestMapPin.h"
#import "RestViewController.h"
#import "MainTableViewController.h"
#interface MapViewController ()
#end
#implementation MapViewController
#synthesize mapView;
- (void)viewDidLoad {
[super viewDidLoad];
_barButton.target = self.revealViewController;
_barButton.action = #selector(revealToggle:);
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
mapView.delegate = self;
/*Babelia*/
MKCoordinateRegion region_Babelia = { {0.0, 0.0}, {0.0, 0.0}};
region_Babelia.center.latitude = 40.4234778;
region_Babelia.center.longitude = -3.686283000000003;
region_Babelia.span.longitudeDelta = 0.1f;
region_Babelia.span.latitudeDelta = 0.1f;
[mapView setRegion:region_Babelia animated:YES];
RestMapPin *ann_Babelia = [[RestMapPin alloc] init];
ann_Babelia.title = #"Babelia";
ann_Babelia.subtitle = #"Barrio de Salamanca";
ann_Babelia.coordinate = region_Babelia.center;
[mapView addAnnotation:ann_Babelia];
/*Bacira*/
MKCoordinateRegion region_Bacira = { {0.0, 0.0}, {0.0, 0.0}};
region_Bacira.center.latitude = 40.43375390000001;
region_Bacira.center.longitude = -3.699036299999989;
region_Bacira.span.longitudeDelta = 0.1f;
region_Bacira.span.latitudeDelta = 0.1f;
[mapView setRegion:region_Bacira animated:YES];
RestMapPin *ann_Bacira = [[RestMapPin alloc] init];
ann_Bacira.title = #"Bacira";
ann_Bacira.subtitle = #"Chamberí";
ann_Bacira.coordinate = region_Bacira.center;
[mapView addAnnotation:ann_Bacira];
/*Indicador de posicion del mapa (para centrarlo)*/
MKCoordinateRegion region_posicion = { {0.0, 0.0}, {0.0, 0.0}};
region_posicion.center.latitude = 40.44934744420573;
region_posicion.center.longitude = -3.695504665374756;
region_posicion.span.longitudeDelta = 0.08f;
region_posicion.span.latitudeDelta = 0.08f;
[mapView setRegion:region_posicion animated:YES];
/*************************************************/
}
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *pinView = nil;
if(annotation != mapView.userLocation) {
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"pin2#2x.png"];
}
else {
//[mapView.userLocation setTitle:#"I am here"];
}
UIButton *pinButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
//if ([[annotation title] isEqualToString:#"Marieta"]) {
//[pinButton addTarget:self action:#selector(annotationView:) forControlEvents:UIControlEventTouchUpInside];
//}
pinView.rightCalloutAccessoryView = pinButton;
return pinView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
RestMapPin *selectedAnnotation = view.annotation;
NSLog(#"Title of selected pin - %#", selectedAnnotation.title);
// Here you get the title of selected annotation
//RestViewController *objYourVC = [[RestViewController alloc]init];
RestViewController *objYourVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier"];
objYourVC.TitleLabel = selectedAnnotation. title;
NSLog(#"objYourVC.TitleLabel - %#", objYourVC.TitleLabel);
//objYourVC.DetailModal.title = selectedAnnotation.title;
//NSLog(#"objYourVC.TitleLabel - %#", objYourVC.TitleLabel);
objYourVC.DescriptionLabel = selectedAnnotation. subtitle;
NSLog(#"objYourVC.DescriptionLabel - %#", objYourVC.DescriptionLabel);
[self.navigationController pushViewController:objYourVC animated:YES];
}
-(IBAction)setMap:(id)sender {
switch (((UISegmentedControl *) sender).selectedSegmentIndex) {
case 0:
mapView.mapType = MKMapTypeStandard;
break;
case 1:
mapView.mapType = MKMapTypeSatellite;
break;
case 2:
mapView.mapType = MKMapTypeHybrid;
break;
default:
break;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Then I am going to show you the view that where I want to get the data of the objYourVC.TitleLabel
This is my RestViewController.h:
#import <UIKit/UIKit.h>
#import "Restaurant.h"
#interface RestViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *TitleLabel;
#property (strong, nonatomic) IBOutlet UILabel *DescriptionLabel;
#property (strong, nonatomic) IBOutlet UIImageView *ImageView;
//#property (strong, nonatomic) IBOutlet NSArray *DetailModal;
#property (weak, nonatomic) IBOutlet UITextView *phoneTextView;
#property (weak, nonatomic) IBOutlet UIButton *webButton;
#property (weak, nonatomic) IBOutlet UITextView *adressTextView;
#property (weak, nonatomic) IBOutlet UIButton *cartaButton;
#property (weak, nonatomic) IBOutlet UITextView *reviewTextView;
#property (weak, nonatomic) IBOutlet UILabel *updateLabel;
#property (nonatomic, strong) Restaurant *DetailModal;
#end
This is my RestViewController.m:
#import "RestViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface RestViewController ()
#end
#implementation RestViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *decDate = #"11/2016";
if ([_DetailModal.title isEqualToString:#"Babelia"]) {
_TitleLabel.text = _DetailModal.title;
_DescriptionLabel.text = _DetailModal.desc;
_ImageView.image = [UIImage imageNamed:_DetailModal.image];
_phoneTextView.text = #"(+34) 918 31 71 79";
_adressTextView.text = #"\n• Callejón de Puigcerdá, 6, Madrid, España";
[_webButton setTitle:#"Web" forState:UIControlStateNormal];
[_webButton addTarget:self action:#selector(openWeb_babelia_Url) forControlEvents:UIControlEventTouchUpInside];
[_cartaButton setTitle:NSLocalizedString (#"Menu", nil) forState:UIControlStateNormal];
[_cartaButton addTarget:self action:#selector(openCarta_babelia) forControlEvents:UIControlEventTouchUpInside];
_reviewTextView.text = NSLocalizedString(#"No reviews available.", nil);
_updateLabel.text = [NSString stringWithFormat:NSLocalizedString(#"Updated: %#", nil), decDate];
}
if ([_DetailModal.title isEqualToString:#"Bacira"]) {
_TitleLabel.text = _DetailModal.title;
_DescriptionLabel.text = _DetailModal.desc;
_ImageView.image = [UIImage imageNamed:_DetailModal.image];
_phoneTextView.text = #"(+34) 91 866 40 30";
_adressTextView.text = #"\n• Calle Del Castillo, 16, Madrid, España";
[_webButton setTitle:#"Web" forState:UIControlStateNormal];
[_webButton addTarget:self action:#selector(openWeb_bacira_Url) forControlEvents:UIControlEventTouchUpInside];
[_cartaButton setTitle:NSLocalizedString (#"Menu", nil) forState:UIControlStateNormal];
[_cartaButton addTarget:self action:#selector(openCarta_bacira) forControlEvents:UIControlEventTouchUpInside];
_reviewTextView.text = NSLocalizedString(#"No reviews available.", nil);
_updateLabel.text = [NSString stringWithFormat:NSLocalizedString(#"Updated: %#", nil), decDate];
}
}
-(void)openWeb_babelia_Url{
UIApplication *application = [UIApplication sharedApplication];
NSURL *URL = [NSURL URLWithString:#"http://babeliarestaurante.com/contactar/"];
[application openURL:URL options:#{} completionHandler:^(BOOL success) {
if (success) {
NSLog(#"Opened url");
}
}];
}
-(void)openWeb_bacira_Url{
UIApplication *application = [UIApplication sharedApplication];
NSURL *URL = [NSURL URLWithString:#"http://www.bacira.es/contacto/4585843222"];
[application openURL:URL options:#{} completionHandler:^(BOOL success) {
if (success) {
NSLog(#"Opened url");
}
}];
}
-(void)openCarta_babelia{
UIApplication *application = [UIApplication sharedApplication];
NSURL *URL = [NSURL URLWithString:#"http://babeliarestaurante.com/nuestra-cocina/las-cartas/"];
[application openURL:URL options:#{} completionHandler:^(BOOL success) {
if (success) {
NSLog(#"Opened url");
}
}];
}
-(void)openCarta_bacira{
UIApplication *application = [UIApplication sharedApplication];
NSURL *URL = [NSURL URLWithString:#"http://www.bacira.es/carta/4591994095"];
[application openURL:URL options:#{} completionHandler:^(BOOL success) {
if (success) {
NSLog(#"Opened url");
}
}];
}
#end
The problem is that the method calloutAccessoryControlTapped: is not working well because the RestViewController.m is not receiving the objYourVC.TitleLabel. What can I do?
When I run the project, the objYourVC.TitleLabel is good in the MapViewController.m (#"Bacira" for example), but when the project goes to RestViewContoller.m the TitleLable is not good, it shows (#"Label").
I know I have a low level of Xcode and I need your help. I am trying to learn more every day. Can anyone help me? Thank you very much.
Edit: This is my Restaurant.h:
#import <Foundation/Foundation.h>
#interface Restaurant : NSObject
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *desc;
#property (nonatomic, copy) NSString *image;
- (instancetype)init:(NSString *)title descripiton:(NSString *)description image:(NSString *)image;
#end
And this is my restaurant.m:
#import "Restaurant.h"
#implementation Restaurant
- (instancetype)init:(NSString *)title descripiton:(NSString *)description image:(NSString *)image {
self = [super init];
if (self != nil) {
self.title = title;
self.desc = description;
self.image = image;
}
return self;
}
#end
You cannot directly deal with IBoutlet , because they have weak reference. o you need to store it an varaible and then in viewDidLoad you need to update the appropriate IBOutlets.
MapViewController.m
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
RestMapPin *selectedAnnotation = view.annotation;
NSLog(#"Title of selected pin - %#", selectedAnnotation.title);
// Here you get the title of selected annotation
//RestViewController *objYourVC = [[RestViewController alloc]init];
RestViewController *objYourVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier"];
objYourVC.DetailModal.pagetitle= selectedAnnotation.title;
objYourVC.DetailModal.pageDescription = selectedAnnotation.desc;
[self.navigationController pushViewController:objYourVC animated:YES];
}
RestViewController.h:
#import <UIKit/UIKit.h>
#import "Restaurant.h"
#interface RestViewController : UIViewController
#property (nonatomic, strong) NSString *pageTitle;
#property (nonatomic, strong) NSString *pageDescription ;
#end
RestViewController.m:
#import "RestViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface RestViewController ()
#end
#implementation RestViewController
- (void)viewDidLoad {
[super viewDidLoad];
_TitleLabel.text = _pageTitle;
_DescriptionLabel.text = _pageDescription;
}
#end
I have a problem when I click on a pin are not sent the correct data. From what I understand even though it has a NSUInteger, these are always changing. How can I fix?
The code is:
DisplayMap.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#import <Parse/Parse.h>
#interface DisplayMap : NSObject <MKAnnotation>
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, copy) NSString *icon;
#property (nonatomic, strong) NSString *Telefono;
#property (nonatomic, strong) NSString *Email;
#property (nonatomic, strong) NSString *Sito;
#property (nonatomic, strong) NSString *TipologiaLocale;
#property (nonatomic, strong) NSString *Cucina;
#property (nonatomic, strong) NSString *Vegano;
#property (nonatomic, strong) NSString *Valutazione;
#property (nonatomic, strong) NSString *Latitudine;
#property (nonatomic, strong) NSString *Longitudine;
#property (nonatomic, strong) NSString *FaceB;
#property (nonatomic, strong) NSString *Twit;
#property (nonatomic, strong) PFFile *Anteprima1;
#property (nonatomic, strong) PFFile *Anteprima2;
#property (nonatomic, strong) PFFile *Anteprima3;
#end
DisplayMap.m
#import "DisplayMap.h"
#implementation DisplayMap
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
#synthesize icon;
#end
Alberghi.h
#import <UIKit/UIKit.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <MapKit/MapKit.h>
#import <Parse/Parse.h>
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
#import "Reachability.h"
#import "TestFlight.h"
#import "MBProgressHUD.h"
#import "DisplayMap.h"
#import "Recipe.h"
#import "DettagliAlberghi.h"
#interface Alberghi : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate> {
MKMapView *_mapView;
}
#property (strong, nonatomic) IBOutlet CLLocationManager *locationManager;
#property (strong, nonatomic) IBOutlet CLGeocoder *geoCoder;
- (IBAction)TornaHome:(id)sender;
#end
Alberghi.m
#import "Alberghi.h"
#interface Alberghi ()
#end
#implementation Alberghi
#synthesize locationManager;
#synthesize geoCoder;
- (void)viewDidLoad {
[super viewDidLoad];
_mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 65, 320, 415)];
[_mapView setDelegate:self];
_mapView.layer.cornerRadius = 5;
locationManager.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
if(IS_OS_8_OR_LATER) {
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
_mapView.showsUserLocation = NO;
[_mapView setMapType:MKMapTypeStandard];
[_mapView setZoomEnabled:YES];
[_mapView setScrollEnabled:YES];
[self.view addSubview:_mapView];
PFQuery *query = [PFQuery queryWithClassName:#"Ristoranti"];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
//NSLog(#"QUERY -----> :%#", objects);
for(NSDictionary *note1 in objects) {
float realLatitude1 = [[note1 objectForKey:#"Latitudine"] floatValue];
float realLongitude1 = [[note1 objectForKey:#"Longitudine"] floatValue];
NSLog(#"(PARSE) Latitudine: %f", realLatitude1);
NSLog(#"(PARSE) Longitudine: %f", realLongitude1);
DisplayMap *displayMap = [[DisplayMap alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = realLatitude1;
theCoordinate.longitude = realLongitude1;
displayMap.coordinate = theCoordinate;
displayMap.title = [note1 objectForKey:#"NomeLocale"];
displayMap.subtitle = [note1 objectForKey:#"Indirizzo"];
displayMap.icon = [note1 objectForKey:#"PinMappa"];
[_mapView setDelegate:self];
[_mapView addAnnotation:displayMap];
}
}
}];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (![annotation isKindOfClass:[DisplayMap class]])
{
return nil;
}
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKAnnotationView *pinView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (pinView == nil)
{
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
}
pinView.canShowCallout = YES;
pinView.annotation = annotation;
DisplayMap *myAnn = (DisplayMap *)annotation;
pinView.image = [UIImage imageNamed:myAnn.icon];
// Create a UIButton object to add on the
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[pinView setRightCalloutAccessoryView:rightButton];
return pinView;
}
- (void)mapView:(MKMapView *)mapView
annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
if ([(UIButton*)control buttonType] == UIButtonTypeDetailDisclosure)
{
[self performSegueWithIdentifier:#"Prova" sender:view];
}
}
#pragma mark - mappa
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
for (MKAnnotationView *annotationView in views) {
if (annotationView.annotation == mapView.userLocation) {
MKCoordinateSpan span = MKCoordinateSpanMake(1.4, 1.4);
MKCoordinateRegion region = MKCoordinateRegionMake(mapView.userLocation.coordinate, span);
[mapView setRegion:region animated:YES];
}
}
}
- (IBAction)TornaHome:(id)sender
{
[self performSegueWithIdentifier:#"TornaHome" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"Prova"]) {
MKAnnotationView *annotationView = sender;
DettagliAlberghi *destViewController =(DettagliAlberghi *) segue.destinationViewController;
DisplayMap *displayMap = (DisplayMap *)annotationView.annotation;
NSLog(#"DisplayMap? %#", displayMap);
NSLog(#"Dettagli Ristorante:\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#
\n%#", displayMap.title, displayMap.subtitle, displayMap.Telefono, displayMap.Email,
displayMap.Sito, displayMap.TipologiaLocale, displayMap.Cucina, displayMap.Vegano,
displayMap.Valutazione, displayMap.Latitudine, displayMap.Longitudine,
displayMap.Anteprima1, displayMap.Anteprima2, displayMap.Anteprima3, displayMap.FaceB,
displayMap.Twit);
destViewController.recipe = displayMap;
/*
MKAnnotationView *annotationView = sender;
NSLog(#"Esporto i dati: %#", annotationView);
DettagliAlberghi *destViewController = segue.destinationViewController;
DisplayMap *displayMap = [[DisplayMap alloc] init];
displayMap.title = [sender objectForKey:#"NomeLocale"];
displayMap.subtitle = [sender objectForKey:#"Indirizzo"];
displayMap.icon = [sender objectForKey:#"PinMappa"];
displayMap.Telefono = [sender objectForKey:#"Telefono"];
displayMap.Email = [sender objectForKey:#"Email"];
displayMap.Sito = [sender objectForKey:#"Sito"];
displayMap.TipologiaLocale = [sender objectForKey:#"TipologiaLocale"];
displayMap.Cucina = [sender objectForKey:#"Cucina"];
displayMap.Vegano = [sender objectForKey:#"Vegano"];
displayMap.Valutazione = [sender objectForKey:#"Valutazione"];
displayMap.Latitudine = [sender objectForKey:#"Latitudine"];
displayMap.Longitudine = [sender objectForKey:#"Longitudine"];
displayMap.Anteprima1 = [sender objectForKey:#"Anteprima1"];
displayMap.Anteprima2 = [sender objectForKey:#"Anteprima2"];
displayMap.Anteprima3 = [sender objectForKey:#"Anteprima3"];
displayMap.FaceB = [sender objectForKey:#"Facebook"];
displayMap.Twit = [sender objectForKey:#"Twitter"];
NSLog(#"Dettagli Ristorante: \n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#\n%#", displayMap.title, displayMap.subtitle, displayMap.Telefono, displayMap.Email, displayMap.Sito, displayMap.TipologiaLocale, displayMap.Cucina, displayMap.Vegano, displayMap.Valutazione, displayMap.Latitudine, displayMap.Longitudine, displayMap.Anteprima1, displayMap.Anteprima2, displayMap.Anteprima3, displayMap.FaceB, displayMap.Twit);
destViewController.recipe = displayMap;
*/
}
}
#end
When I click on the pin, the app crashes. I added an NSLog in PrepareToSegue and I noticed that all the fields to export in View next are empty, however, the data is read through PFQuery in viewDidLoad. What's wrong? When I click the pin does not export the data required?
2014-11-29 08:08:16.190 Veg[1083:8473] (PARSE) Latitudine: 45.435745
2014-11-29 08:08:16.190 Veg[1083:8473] (PARSE) Longitudine: 10.986951
2014-11-29 08:08:16.191 Veg[1083:8473] (PARSE) Latitudine: 45.441578
2014-11-29 08:08:16.191 Veg[1083:8473] (PARSE) Longitudine: 10.982130
2014-11-29 08:08:29.102 Veg[1083:8473] DisplayMap? <DisplayMap: 0x7f90335b71f0>
2014-11-29 08:08:29.102 Veg[1083:8473] Dettagli Ristorante:
La Lanterna
Piazzetta Portichetti, 6 Verona
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
2014-11-29 08:08:29.301 Veg[1083:8473] Double Coord: 0.000000, 0.000000
2014-11-29 08:08:31.356 Veg[1083:8473] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
I can not understand how to order ... always in the same order every time you open the View are always changing position and consequently when I click on a Pin View opens me different and not the one you want. Solutions? Thanks in advance
Update, add this in your viewDidLoad (in ViewController):
displayMap.icon = [note1 objectForKey:#"PinMappa"];
// Add this
displayMap.Telefono = [note1 objectForKey:#"Telefono"];
displayMap.Email = [note1 objectForKey:#"Email"];
displayMap.Sito = [note1 objectForKey:#"Sito"];
displayMap.FaceB = [note1 objectForKey:#"Facebook"];
displayMap.Twit = [note1 objectForKey:#"Twitter"];
displayMap.Cucina = [note1 objectForKey:#"Cucina"];
displayMap.TipologiaLocale = [note1 objectForKey:#"TipologiaLocale"];
displayMap.Valutazione = [note1 objectForKey:#"Valutazione"];
displayMap.Vegano = [note1 objectForKey:#"Vegano"];
// End of adding
[_mapView setDelegate:self];
Hi I assume you are using ARC, I'm afraid you have copied your code from a very old font, In fact a couple of them. (On example you have three instances variable what's name is title, one for the Protocol, and a couple of them on created an other from the property, with wrong synthesised). And the dealloc method better don't speak.
Well change your code to this: (Don´t worry It has the same variable you need (without duplicates).
DispalyMap.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <Parse/Parse.h>
#interface DisplayMap : NSObject <MKAnnotation>
#property (nonatomic, copy) NSString *icon;
#property (nonatomic, strong) NSString *Telefono;
#property (nonatomic, strong) NSString *Email;
#property (nonatomic, strong) NSString *Sito;
#property (nonatomic, strong) NSString *TipologiaLocale;
#property (nonatomic, strong) NSString *Cucina;
#property (nonatomic, strong) NSString *Vegano;
#property (nonatomic, strong) NSString *Valutazione;
#property (nonatomic, strong) NSString *Latitudine;
#property (nonatomic, strong) NSString *Longitudine;
#property (nonatomic, strong) NSString *FaceB;
#property (nonatomic, strong) NSString *Twit;
#property (nonatomic, strong) PFFile *Anteprima1;
#property (nonatomic, strong) PFFile *Anteprima2;
#property (nonatomic, strong) PFFile *Anteprima3;
#end
Display.m: (Only this)
#implementation DisplayMap
#synthesize coordinate = _coordinate;
#synthesize title = _title;
#synthesize subtitle = _subtitle;
#end
Well, I need to help you the crash message (because If with this change your App don't work, probably the mistake could be in the new view controller).
// Old answer:
I can't understand your code 100% because there are some code missing, but I think you made lot´s of thing you don't need. Try this methods, (Comment your current methods, and paste this).
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (![annotation isKindOfClass:[DisplayMap class]])
{
return nil;
}
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKAnnotationView *pinView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (pinView == nil)
{
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
}
pinView.canShowCallout = YES;
pinView.annotation = annotation;
DisplayMap *myAnn = (DisplayMap *)annotation;
pinView.image = [UIImage imageNamed:myAnn.icon];
// Create a UIButton object to add on the
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[pinView setRightCalloutAccessoryView:rightButton];
return pinView;
}
- (void)mapView:(MKMapView *)mapView
annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
if ([(UIButton*)control buttonType] == UIButtonTypeDetailDisclosure)
{
[self performSegueWithIdentifier:#"Prova" sender:view];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"Prova"]) {
MKAnnotationView *annotationView = sender;
DettagliAlberghi *destViewController =(DettagliAlberghi *) segue.destinationViewController;
DisplayMap *displayMap = (DisplayMap *)annotationView.annotation;
destViewController.recipe = displayMap;
}
}
I am trying to provide directions to certain areas I have marked with map pins on my map view. On those pins I have displayed the name of the location and where it is located. I would like for them to be able to click the "i" that is usually on some Apple "pop ups" and it direct them to the Maps app and give them directions based on the coordinates I programmed in to place the map pin where it is. I will post two pictures first of what I have and what I would like to accomplish.
What I have right now
What I want to add to my pin (just the "i")
Now I will post my code of how I accomplished my first screenshot.
ViewController.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController
{
MKMapView *mapView;
}
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
-(IBAction)SetMap:(id)sender;
-(IBAction)GetLocation:(id)sender;
-(IBAction)Directions:(id)sender;
#end
ViewController.m:
#import "ViewController.h"
#import "MapPin.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize mapView;
- (void)viewDidLoad
{
[super viewDidLoad];
//Moss Preserve coordinates
MKCoordinateRegion MossPreserveRegion = { {0.0, 0.0}, {0.0, 0.0}};
MossPreserveRegion.center.latitude = 33.3816566;
MossPreserveRegion.center.longitude = -86.8415451;
MossPreserveRegion.span.longitudeDelta = 55.0;
MossPreserveRegion.span.latitudeDelta = 55.0;
[mapView setRegion:MossPreserveRegion animated:YES];
//Moss Preserve annotation and map pin
MapPin *MossPreserveAnnotation = [[MapPin alloc] init];
MossPreserveAnnotation.title = #"Moss Rock Preserve Boulder Fields";
MossPreserveAnnotation.subtitle = #"Hoover, AL";
MossPreserveAnnotation.coordinate = MossPreserveRegion.center;
[mapView addAnnotation:MossPreserveAnnotation];
//Horse Pens 40 coordinates
MKCoordinateRegion HorsePenRegion = { {0.0, 0.0}, {0.0, 0.0}};
HorsePenRegion.center.latitude = 33.9207535;
HorsePenRegion.center.longitude = -86.3089447;
HorsePenRegion.span.longitudeDelta = 55.0;
HorsePenRegion.span.latitudeDelta = 55.0;
[mapView setRegion:HorsePenRegion animated:YES];
//Horse Pens 40 annotation and map pin
MapPin *HorsePenAnnotation = [[MapPin alloc] init];
HorsePenAnnotation.title = #"Horse Pens 40";
HorsePenAnnotation.subtitle = #"Steele, AL ";
HorsePenAnnotation.coordinate = HorsePenRegion.center;
[mapView addAnnotation:HorsePenAnnotation];
// Create an MKMapItem to pass to the Maps app
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:MossPreserveAnnotation.coordinate
addressDictionary:nil];
MKMapItem *mossPreserveMapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mossPreserveMapItem setName:MossPreserveAnnotation.title];
NSDictionary *launchOptions = #{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving};
// Get the "Current User Location" MKMapItem
placemark = [[MKPlacemark alloc] initWithCoordinate:HorsePenRegion.coordinate
addressDictionary:nil];
MKMapItem *horsePenMapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
horsePenmapItem.name = HorsePenRegion.title;
// Pass the current location and destination map items to the Maps app
// Set the direction mode in the launchOptions dictionary
[MKMapItem openMapsWithItems:#[mossPreserveMapItem, horsePenmapItem]
launchOptions:launchOptions];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)SetMap:(id)sender;
{
switch (((UISegmentedControl *) sender).selectedSegmentIndex)
{
case 0:
mapView.mapType = MKMapTypeStandard;
break;
case 1:
mapView.mapType = MKMapTypeSatellite;
break;
case 2:
mapView.mapType = MKMapTypeHybrid;
break;
default:
break;
}
}
-(IBAction)GetLocation:(id)sender;
{
mapView.showsUserLocation = YES;
}
-(IBAction)Directions:(id)sender;
{
NSString *urlString = #"http://maps.apple.com/maps?daddr=33.3816566,-86.8415451";
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}
#end
MapPin.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
MapPin.m:
#import "MapPin.h"
#implementation MapPin
#synthesize coordinate, title, subtitle;
#end
I see this all of the time in apps that I use. i just don't even really know what it is called, so I could even search for it. I am not looking for someone to hold my hand and tell me the answer, just some proper guidance and constructive criticism.
Thanks
Is this what you need?
#import "MapViewController.h"
#import "MapPin.h"
#import MapKit;
#interface MapViewController ()<MKMapViewDelegate>
#property (nonatomic, weak) IBOutlet MKMapView *mapView;
#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];
_mapView.delegate = self;
//Moss Preserve coordinates
MKCoordinateRegion MossPreserveRegion = { {0.0, 0.0}, {0.0, 0.0}};
MossPreserveRegion.center.latitude = 33.3816566;
MossPreserveRegion.center.longitude = -86.8415451;
MossPreserveRegion.span.longitudeDelta = 55.0;
MossPreserveRegion.span.latitudeDelta = 55.0;
[_mapView setRegion:MossPreserveRegion animated:YES];
//Moss Preserve annotation and map pin
MapPin *MossPreserveAnnotation = [[MapPin alloc] init];
MossPreserveAnnotation.title = #"Moss Rock Preserve Boulder Fields";
MossPreserveAnnotation.subtitle = #"Hoover, AL";
MossPreserveAnnotation.coordinate = MossPreserveRegion.center;
[_mapView addAnnotation:MossPreserveAnnotation];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
// Create an MKMapItem to pass to the Maps app
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:view.annotation.coordinate
addressDictionary:nil];
MKMapItem *mossPreserveMapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mossPreserveMapItem setName:view.annotation.title];
NSDictionary *launchOptions = #{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving};
// Get the "Current User Location" MKMapItem
MKMapItem *currentLocationItem = [MKMapItem mapItemForCurrentLocation];
[MKMapItem openMapsWithItems:#[mossPreserveMapItem, currentLocationItem]
launchOptions:launchOptions];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"MKPinAnnotationView"];
annotationView.canShowCallout = YES;
UIButton *detailButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
annotationView.rightCalloutAccessoryView = detailButton;
return annotationView;
}
You need to create 2 map items for your locations and pass as arguments to MKMapItem's openMapsWithItems:launchOptions:
// Create an MKMapItem to pass to the Maps app
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:MossPreserveAnnotation.coordinate
addressDictionary:nil];
MKMapItem *mapItem1 = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:MossPreserveAnnotation.title];
NSDictionary *launchOptions = #{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving};
// Get the "Current User Location" MKMapItem
placemark = [[MKPlacemark alloc] initWithCoordinate:HorsePenAnnotation.coordinate
addressDictionary:nil];
MKMapItem *mapItem2 = [[MKMapItem alloc] initWithPlacemark:placemark];
mapItem2.name = HorsePenAnnotation.title;
// Pass the current location and destination map items to the Maps app
// Set the direction mode in the launchOptions dictionary
[MKMapItem openMapsWithItems:#[mapItem1, mapItem2]
launchOptions:launchOptions];
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:";.
I have this code:
// MapViewController.h
#import <Foundation/Foundation.h>
#import "MyCLController.h"
#import <MapKit/MapKit.h>
#class ShowsContainerController;
#interface MapViewController : UIViewController <MyCLControllerDelegate,MKMapViewDelegate> {
MyCLController *locationController;
MKMapView *mapView;
}
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property (assign) BOOL updateMap;
#property (strong) ShowsContainerController *parent;
#end
// MapViewController.m
#import "MapViewController.h"
#import "ShowsContainerController.h"
#define METERS_PER_MILE 1609.344
#implementation MapViewController
#synthesize parent, mapView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.updateMap = YES;
locationController = [[MyCLController alloc] init];
locationController.delegate = self;
[locationController.locationManager startUpdatingLocation];
mapView.delegate = self;
}
- (void)locationUpdate:(CLLocation *)location {
if( self.updateMap ){
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
[mapView setRegion:viewRegion animated:YES];
self.parent = (ShowsContainerController *)self.parentViewController;
[self.parent setLocation:location];
self.updateMap = NO;
}
}
- (void)locationError:(NSError *)error {
NSLog([error localizedDescription]);
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.parent.mapReady = YES;
if( self.parent.locationSet ){
[self.parent callApi];
}
}
#pragma mark MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"delegating user location");
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
NSLog(#"delegating pins");
static NSString* ShowAnnotationIdentifier = #"showAnnotationIdentifier";
MKPinAnnotationView* pinView = (MKPinAnnotationView *)
[mapView dequeueReusableAnnotationViewWithIdentifier:ShowAnnotationIdentifier];
if (!pinView)
{
// if an existing pin view was not available, create one
MKPinAnnotationView* customPinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:ShowAnnotationIdentifier];
customPinView.enabled = YES;
customPinView.pinColor = MKPinAnnotationColorRed;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
return customPinView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
#pragma mark -
#end
And here's the code adding my pins; it isn't fired until an api call is made, which is after viewDidAppear is fired:
- (void)placeAnnotations:(NSArray *)shows
{
NSEnumerator *e = [shows objectEnumerator];
id show;
NSMutableArray *annotations = [[NSMutableArray alloc] init];
while (show = [e nextObject]) {
double lat = [[[[[show objectForKey:#"venue"] objectForKey:#"location"] objectForKey:#"geo:point"] objectForKey:#"geo:lat"] doubleValue];
double lng = [[[[[show objectForKey:#"venue"] objectForKey:#"location"] objectForKey:#"geo:point"] objectForKey:#"geo:long"] doubleValue];
ShowAnnotation *annotation = [[ShowAnnotation alloc]
initWithCoordinate:CLLocationCoordinate2DMake(lat, lng)
withMap:self.mapController.mapView
withTitle:[show objectForKey:#"title"]
withSubtitle:[[show objectForKey:#"venue"] objectForKey:#"name" ]];
[annotations addObject:annotation];
}
NSLog(#"adding annotations");
[self.mapController.mapView addAnnotations:annotations];
}
The log shows "delegating user location", but never "delegating pins". It doesn't even fire viewForAnnotation more than the one initial time for the user's location.
The delegation seems to be working, otherwise I wouldn't be able to capture this selector, but why is it firing for only the user location and not firing for subsequent annotation additions?