Pulling coordinates for MapView annotations from MySQL database, but annotations aren't showing? - objective-c

I'm trying to pull coordinates for my MapView from a MySQL database, but for some reason my coordinates just aren't showing up on the MapView?
See below my code.
MapViewController.h file
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController <MKMapViewDelegate>
#property (nonatomic, strong) IBOutlet MKMapView *mapView;
#property (nonatomic, retain) NSMutableArray *dispensaries;
#property (nonatomic, retain) NSMutableData *data;
#end
MapViewController.m
#import "MapViewController.h"
#import "MapViewAnnotation.h"
#import "JSONKit.h"
#implementation MapViewController
#synthesize mapView;
#synthesize dispensaries;
#synthesize data;
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidUnload];
NSLog(#"Getting Device Locations");
NSString *hostStr = #"http://stylerepublicmagazine.com/dispensaries.php";
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:hostStr]];
NSString *serverOutput = [[NSString alloc] initWithData:dataURL encoding: NSASCIIStringEncoding];
NSLog(#"server output: %#", serverOutput);
NSMutableArray *array = [[[serverOutput objectFromJSONString] mutableCopy] autorelease];
dispensaries = [serverOutput objectFromJSONString];
NSLog(#"%#", [serverOutput objectFromJSONString]);
for (NSDictionary *dictionary in array) {
assert([dictionary respondsToSelector:#selector(objectForKey:)]);
CLLocationCoordinate2D coord = {[[dictionary objectForKey:#"lat"] doubleValue], [[dictionary objectForKey:#"lng"] doubleValue]};
MapViewAnnotation *ann = [[MapViewAnnotation alloc] init];
ann.title = [dictionary objectForKey:#"Name"];
ann.coordinate = coord;
[mapView addAnnotation:ann];
}
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
self.mapView.delegate = self;
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = userLocation.coordinate;
point.title = #"You Are Here";
point.subtitle = #"Your current location";
[self.mapView addAnnotation:point];
}
MapViewAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#import <CoreLocation/CoreLocation.h>
#interface MapViewAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
MapViewAnnotation.m
#import "MapViewAnnotation.h"
#implementation MapViewAnnotation
#synthesize title, coordinate, subtitle;
-(void)dealloc{
[title release];
[super dealloc];
}
#end

this seems to be an issue with you expecting the wrong JSON:
You wrap the serverOutput in an array:
NSMutableArray *array = [NSMutableArray arrayWithObject:[serverOutput objectFromJSONString]];
You try to access a JKDictionary (Json Kit dictionary) WITCH is infact an array and therefore doesn't answer to objectForKey:
try to make sure:
for (NSDictionary *dictionary in array) {
assert([dictionary respondsToSelector:#selector(objectForKey:)]);
--
potential Solution
I believe your extra wrapping makes it bad. try:
NSMutableArray *array = [[[serverOutput objectFromJSONString] mutableCopy] autorelease];

Related

How to add directions among two custom locations in Mapview for IOS 7 (objective c)

I have to add directions among two custom locations in IOS 7.
Any one tell me please.
Thanks.
Try this:
1.Create a file named ViewController with MKMapView as an IBOutlet and connect the map view from Storyboard to MKMapView property.
[ViewController.h]
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <MapKit/MKAnnotation.h>
#interface ViewController : UIViewController <MKMapViewDelegate>
#property (nonatomic, strong) IBOutlet MKMapView *mapView;
#end
[ViewController.m]
#import "ViewController.h"
#import "Annotation.h"
#define Location1Latitude -12.429481
#define Location1Longitude 130.863324
#define Location2Latitude -32.15037
#define Location2Longitude 115.782909
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mapView.delegate = self;
[self.mapView setMapType:MKMapTypeStandard];
[self.mapView setZoomEnabled:YES];
[self.mapView setScrollEnabled:YES];
//Annotation
NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
Annotation * myAnn;
// Location 1 Annotation
myAnn = [[Annotation alloc] init];
location.latitude = Location1Latitude;
location.longitude = Location1Longitude;
[locations addObject:myAnn];
//Location 2 Annotation
myAnn = [[Annotation alloc] init];
location.latitude = Location2Latitude;
location.longitude = Location2Longitude;
myAnn.coordinate = location;
[locations addObject:myAnn];
[self.mapView addAnnotations:locations];
[self performSelector:#selector(drawRoute) withObject:self afterDelay:1.0];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)drawRoute {
MKPlacemark *source = [[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(Location1Latitude, Location1Longitude) addressDictionary:nil];
MKMapItem *srcMapItem = [[MKMapItem alloc]initWithPlacemark:source];
[srcMapItem setName:#"source"];
MKPlacemark *destination = [[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(Location2Latitude, Location2Longitude) addressDictionary:nil ];
MKMapItem *destMapItem = [[MKMapItem alloc]initWithPlacemark:destination];
[destMapItem setName:#"dest"];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
[request setSource:srcMapItem];
[request setDestination:destMapItem];
[request setTransportType:MKDirectionsTransportTypeAutomobile];
MKDirections *direction = [[MKDirections alloc]initWithRequest:request];
[direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
NSLog(#"response = %# \n eror %#",response, error);
NSArray *arrRoutes = [response routes];
[arrRoutes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
MKRoute *rout = obj;
MKPolyline *line = [rout polyline];
[self.mapView addOverlay:line];
NSLog(#"Rout Name : %#",rout.name);
NSLog(#"Total Distance (in Meters) :%f",rout.distance);
NSArray *steps = [rout steps];
NSLog(#"Total Steps : %lu",(unsigned long)[steps count]);
[steps enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Rout Distance : %f",[obj distance]);
NSLog(#"Rout Instruction : %#",[obj instructions]);
}];
}];
}];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.strokeColor = [UIColor colorWithRed:55.0/255.0 green:160.0/255.0 blue:250.0/255.0 alpha:1.0];
renderer.lineWidth = 4.0;
return renderer;
}
2.Create a file named Annotation.
[Annotation.h]
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface Annotation : NSObject <MKAnnotation>
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString * title;
#property(nonatomic, copy) NSString * subtitle;
#property(nonatomic, copy) NSString * imageName;
#end
[Annotation.m]
#import "Annotation.h"
#implementation Annotation
#end

CoreLocation wont compile - same set-up as another working project

CoreLocation wont compile because of this line
LocationAnnotation *annotation = [[LocationAnnotation alloc] initWithTitle:#"Point to home?" andCoordinate:newLocation.coordinate andSubtitle:nil];
I've tried everything and am now bored of relinking coreLoction
If I comment out that line CoreLocation compiles fine.
I have included corelocation and mapkit in the build phase, I have no framework search paths
Undefined symbols for architecture i386:
"_OBJC_CLASS_$_LocationAnnotation", referenced from:
objc-class-ref in JobMapVC.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have used this code in another project an it compiles fine, what am I missing?
The main controller
JobMapVC.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "LocationAnnotation.h"
#interface JobMapVC : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>
{
NSString *address;
#private
CLLocationManager *locationManager;
}
#property (nonatomic, strong) NSString *address;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, assign, readwrite) double homeLatitude;
#property (nonatomic, assign, readwrite) double homeLongitude;
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
- (IBAction)dismissMap:(id)sender;
#end
JobMapVC.m
#import "JobMapVC.h"
#import "LocationAnnotation.h"
#interface JobMapVC ()
#end
#implementation JobMapVC
{
}
#synthesize address = _address;
#synthesize locationManager = _locationManager;
- (void)viewDidLoad
{
[super viewDidLoad];
[self searchCoordinatesForAddress:_address];
}
- (void) searchCoordinatesForAddress:(NSString *)inAddress{
NSString *cleanAddress = [[inAddress componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:#" "];
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?sensor=true&address=%#",cleanAddress];
[urlString setString:[urlString stringByReplacingOccurrencesOfString:#" " withString:#"+"]];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSError* error;
NSURLResponse *response;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSDictionary* georesults = [NSJSONSerialization
JSONObjectWithData:returnData
options:NSJSONReadingMutableContainers | NSJSONReadingAllowFragments
error:&error];
if ( [[georesults objectForKey:#"status"] isEqualToString:#"OK"] )
{
double latitude = [[[[[[georesults objectForKey:#"results"]objectAtIndex:0] objectForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lat"] doubleValue];
double longitude = [[[[[[georesults objectForKey:#"results"]objectAtIndex:0] objectForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lng"] doubleValue];
NSLog(#"lat:%f", latitude );
[self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
}
}
- (void) zoomMapAndCenterAtLatitude:(double)latitude andLongitude:(double)longitude
{
MKCoordinateRegion region;
region.center.latitude = latitude;
region.center.longitude = longitude;
//Set Zoom level using Span
MKCoordinateSpan span;
span.latitudeDelta = .005;
span.longitudeDelta = .005;
region.span = span;
//Move the map and zoom
[_mapView setRegion:region animated:YES];
// Map pin
CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
// THIS LINE STOP coreLocation from compiling !!!
LocationAnnotation *annotation = [[LocationAnnotation alloc] initWithTitle:#"Point to home?" andCoordinate:newLocation.coordinate andSubtitle:nil];
[self.mapView addAnnotation:annotation];
[self.mapView selectAnnotation:annotation animated:YES];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"locationManager:%# didFailWithError:%#", manager, error);
if (error.code == kCLErrorDenied)
{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Error!"
message:#"This can not work without location services enabled"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
- (IBAction)dismissMap:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
The LocationAnnotation file which I've used exactly as is in another project without any issues
LocationAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface LocationAnnotation : NSObject <MKAnnotation> {
}
#property (strong) NSString *title;
#property (strong) NSString *subtitle;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d andSubtitle:(NSString *)sbttl;
#end
LocationAnnotation.m
#import "LocationAnnotation.h"
#implementation LocationAnnotation
#synthesize title, subtitle, coordinate;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d andSubtitle:(NSString *)sbttl {
if ((self = [super init])) {
title = ttl;
subtitle = sbttl;
coordinate = c2d;
}
return self;
}
#end
The weird thing is the - (id)initWithTitle line wont colour the syntax properly. This code works ion one project but not another...??!!
Your code compiles, it's the linker that's reporting the problem. The linker cannot find your LocationAnnotation class, because it probably wasn't compiled. Select the LocationAnnotation.m in Xcode and in the File Inspector (in the right tray) and make sure that the file is a member of your target:

Map coordinates not decoding

In my app, I am trying to save the pins that are on the map so that they are there when the user opens the app after it is terminated. I have conformed my mkAnnotation class to NSCoding, and implemented the two required methods. The annotations are all stored in a NSMutableArray in a singleton class, so I am really just trying to save the array in the singleton class. Everything is being encoded fine, but I do not think they are being decoded. Here is some code:
This is my MKAnnotation class:
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface MapPoint : NSObject <MKAnnotation, NSCoding>
{
}
- (id)initWithAddress:(NSString*)address
coordinate:(CLLocationCoordinate2D)coordinate
title:(NSString *)t;
#property (nonatomic, readwrite) CLLocationCoordinate2D coordinate;
//This is an optional property from MKAnnotataion
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readonly, copy) NSString *subtitle;
#property (nonatomic) BOOL animatesDrop;
#property (nonatomic) BOOL canShowCallout;
#property (copy) NSString *address;
#property (nonatomic, copy) NSString *imageKey;
#property (nonatomic, copy) UIImage *image;
#end
#implementation MapPoint
#synthesize title, subtitle, animatesDrop, canShowCallout, imageKey, image;
#synthesize address = _address, coordinate = _coordinate;
-(id)initWithAddress:(NSString *)address
coordinate:(CLLocationCoordinate2D)coordinate
title:(NSString *)t {
self = [super init];
if (self) {
_address = [address copy];
_coordinate = coordinate;
[self setTitle:t];
NSDate *theDate = [NSDate date];
subtitle = [NSDateFormatter localizedStringFromDate:theDate
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterShortStyle];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_address forKey:#"address"];
NSLog(#"ENCODING coordLatitude %f coordLongitude %f ", _coordinate.latitude, _coordinate.longitude);
[aCoder encodeDouble:_coordinate.longitude forKey:#"coordinate.longitude"];
[aCoder encodeDouble:_coordinate.latitude forKey:#"coordinate.latitude"];
[aCoder encodeObject:title forKey:#"title"];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
[self setAddress:[aDecoder decodeObjectForKey:#"address"]];
NSLog(#"DECODING coordLatitude %f coordLongitude %f ", _coordinate.latitude, _coordinate.longitude);
_coordinate.longitude = [aDecoder decodeDoubleForKey:#"coordinate.longitude"];
_coordinate.latitude = [aDecoder decodeDoubleForKey:#"coordinate.latitude"];
[self setTitle:[aDecoder decodeObjectForKey:#"title"]];
}
return self;
}
#end
Here is my singleton class:
#import <Foundation/Foundation.h>
#class MapPoint;
#interface Data : NSObject
{
NSMutableArray *_annotations;
}
#property (retain, nonatomic) NSMutableArray *annotations;
+ (Data *)singleton;
- (NSString *)pinArchivePath;
- (BOOL)saveChanges;
#end
#implementation Data
#synthesize annotations = _annotations;
+ (Data *)singleton {
static dispatch_once_t pred;
static Data *shared = nil;
dispatch_once(&pred, ^{
shared = [[Data alloc] init];
shared.annotations = [[NSMutableArray alloc]init];
});
return shared;
}
- (id)init {
self = [super init];
if (self) {
NSString *path = [self pinArchivePath];
_annotations = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
if (!_annotations) {
_annotations = [[NSMutableArray alloc]init];
}
}
return self;
}
- (NSString *)pinArchivePath {
NSArray *cachesDirectories = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [cachesDirectories objectAtIndex:0];
return [cachesDirectory stringByAppendingPathComponent:#"pins.archive"];
}
- (BOOL)saveChanges {
NSString *path = [self pinArchivePath];
return [NSKeyedArchiver archiveRootObject:[Data singleton].annotations
toFile:path];
}
#end
In my viewDidLoad method on the map view controller, I try and place the annotations in the singleton array on the map with this:
for (MapPoint *mp in [Data singleton].annotations) {
[_worldView addAnnotation:mp];
}
The main problem is in the singleton method in these lines:
dispatch_once(&pred, ^{
shared = [[Data alloc] init];
shared.annotations = [[NSMutableArray alloc]init]; //<-- problem line
});
The shared = [[Data alloc] init]; line decodes and initializes the annotations array.
Then the shared.annotations = [[NSMutableArray alloc]init]; line re-creates and re-initializes the annotations array thus discarding the just-decoded annotations so the singleton always returns an empty array.
Remove the shared.annotations = [[NSMutableArray alloc]init]; line.
As already mentioned in the comment, the other minor issue, which causes simply confusion, is the placement of the NSLog where the coordinate is being decoded. The NSLog should be after the decode is done.

iOS mapview - trouble when adding annotations

Trying to add some annotations for a MapView, but keep getting an ARC Semantic issue: 'No visible #interface for 'MKPointAnnotation' declares the selector initWithTitle:andCoordinate:
I'm fairly new to this so don't really know what it means, if anyone could explain/correct it i'd be grateful.
Here is my viewDidLoad method:
- (void)viewDidLoad
{
CLLocationCoordinate2D location;
location.latitude = (double) 51.501468;
location.longitude = (double) -0.141596;
MKPointAnnotation *newAnnotation = [[MKPointAnnotation alloc] initWithTitle:#"Buckingham Palace" andCoordinate:location];
[self._mapView addAnnotation:newAnnotation];
}
and my header file:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapViewAnnotation : NSObject <MKAnnotation> {
NSString *title;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d;
#end
The initWithTitle:andCoordinate method you created is a method of MapViewAnnotation rather than MKPointAnnotation.
You probably want:
MapViewAnnotation *newAnnotation = [[MapViewAnnotation alloc] initWithTitle:#"Buckingham Palace" andCoordinate:location];
[self._mapView addAnnotation:newAnnotation];
It's trying to tell you it can't find any method that matches the signature of initWithTitle:andCoordinate:
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:coordinate];
[annotation setTitle:#"Buckingham Palace"];

selectAnnotation does not show callout

I want to change the callout shown on the MKMapView. When I call
[self.mapView selectAnnotation:annotation animated:YES];
it pans the map to the annotation, but does not show its callout. How do I get it to show the callout?
Set the title, and optionally the subtitle property on the annotation object. MapKit will automatically show a callout.
#interface MyAnnotation : NSObject <MKAnnotation> {
NSString *title;
NSString *subtitle;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
And the implementation,
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize title, subtitle;
#end
Usage,
MyAnnotation *foo = [[MyAnnotation alloc] init];
foo.title = #"I am Foo";
foo.subtitle = "I am jus' a subtitle";
You should implement the MKAnnotation Delegate method
-(MKAnnotationView *)mapView:(MKMapView *)_mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
static NSString *AnnotationViewIdentifier = #"AnnotationViewIdentifier";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewIdentifier];
if (annotationView == nil)
{
annotationView = [[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:AnnotationViewIdentifier]autorelease];
}
annotationView.canShowCallout = YES;
return annotationView;
}