Obj-c - Crash when passing data to detailview? - ios

I'm passing data from my ViewController to a detailViewController with the below code, however no matter what I seem to do, my app crashes at the line
self.username.text = self.mapuserData[#"users_name"];
with the following error (even though data is present in self.mapuserData)? Help!
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSArrayI
objectForKeyedSubscript:]: unrecognized selector sent to instance
0x17126b840'
ViewController.m
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(calloutTapped:)];
[view addGestureRecognizer:tapGesture];
}
-(void)calloutTapped:(UITapGestureRecognizer *) sender
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
OtherUserViewController *yourViewController = (OtherUserViewController *)[storyboard instantiateViewControllerWithIdentifier:#"OtherUserViewController"];
NSMutableDictionary *dictionary = [self.addressData mutableCopy];
yourViewController.mapuserData = dictionary; // this is how you do it
[self.navigationController pushViewController:yourViewController animated:YES];
}
OtherViewController.m (detailview)
- (void)viewDidLoad {
[super viewDidLoad];
if ([self.mapuserData count] > 0) {
NSLog(#"This is map user data %#", self.mapuserData);
self.addFriend.hidden = NO;
self.username.text = self.mapuserData[#"users_name"];
self.userBio.text = self.mapuserData[#"userbio"];
NSString *thirdLink = self.mapuserData[#"photo_path"];
NSString *ImageURLTwo = thirdLink;
NSData *imageDataTwo = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURLTwo]];
self.userPhoto.image = [[UIImage alloc] initWithData:imageDataTwo];
}
}
Here's what's in self.mapuserData:
This is map user data (
{
address = "2957 fake street";
childrenunder = Yes;
city = Vancouver;
"emergency facility" = None;
"first name" = josh;
"last name" = tree;
phone = 6046710890;
"photo_path" = "http://url.ca/paw.png";
"points balance" = 24;
"postal code" = b6b6v5;
"profile photo" = "<null>";
"property type" = Apartment;
province = bc;
"special skills" = "Medication";
"star rating" = 0;
"street_address" = none;
supervision = Yes;
uid = 182;
userbio = nfkkdkckmfkekxkx;
"users_name" = "josh_tree#hotmail.com";

Create your own class to store index of the Annotation data source. Which is subclass of MKPointAnnotation
PointAnnotation.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface PointAnnotation : MKPointAnnotation
#property (nonatomic, assign)int index;
#end
PointAnnotation.m
#import "PointAnnotation.h"
#implementation PointAnnotation
#end
Change your Add Annotation code like below
int index = 0; //Index to track the data source index while select the annotation call out view.
for (NSMutableDictionary *multiplelocations in self.addressData) {
NSString *location = multiplelocations[#"street_address"];
NSLog(#"Pull addresses %#", location);
NSString *userNames = multiplelocations[#"users_name"];
NSString *userBio = multiplelocations[#"userbio"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 8.0;
region.span.latitudeDelta /= 8.0;
PointAnnotation *point = [[PointAnnotation alloc] init];
point.coordinate = placemark.coordinate;
point.title = userNames;
point.subtitle = userBio;
point.index = index; // Store index here.
[self.mapView addAnnotation:point];
}
}
];
index = index + 1;
}
And modify your didSelectAnnotationView code like below
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
//Get the annotation object from callout view.
PointAnnotation *selectedPoint = (PointAnnotation *) view.annotation;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
OtherUserViewController *yourViewController = (OtherUserViewController *)[storyboard instantiateViewControllerWithIdentifier:#"OtherUserViewController"];
//Get the dictionary from array by using the index of the custom PointAnnoation object.
NSMutableDictionary *dictionary = self.addressData[selectedPoint.index];
yourViewController.mapuserData = dictionary;
[self.navigationController pushViewController:yourViewController animated:YES];
}
You are assigning an Array to Dictionary which is wrong.
NSMutableDictionary *dictionary = [self.addressData mutableCopy];
yourViewController.mapuserData = dictionary;

The Dictionary you are expecting is the array type at the run time so you need change the code above
NSMutableDictionary *dictionary = [self.addressData[0] mutableCopy];
change addressData to NSArray

self.mapuserData is no more deserializes into dictionary, It is deserializes into array.
So what you want to do is:
Get an object from zero index form self.mapuserData and then save as dictionary.
Example : NSDictionary *dict = self.mapuserData[0];
self.mapuserData should be type of array.

Related

Obj-C - Custom Map Annotation Callout View from XIB

I'm trying to have a custom view/XIB display when an annotation on my MapView is tapped. That said, I've found various answers to this question for swift - but none for objective C.
Currently, I'm able to display custom annotations with the following code:
ViewController.m
-(void)viewDidLoad {
NSMutableDictionary *viewParamsFriend = [NSMutableDictionary new];
[viewParamsFriend setValue:#"accepted_friends" forKey:#"view_name"];
[DIOSView viewGet:viewParamsFriend success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.friendData = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *multiplelocationsFriend in self.friendData) {
NSString *location = multiplelocationsFriend[#"address2"];
NSString *userNames = multiplelocationsFriend[#"node_title"];
NSString *userBio = multiplelocationsFriend[#"body"];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.friendsMapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
PointAnnotation *point = [[PointAnnotation alloc] init];
point.coordinate = placemark.coordinate;
point.title = userNames;
point.subtitle = userBio;
point.index = index; // Store index here.
[self.friendsMapView addAnnotation:point];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
MKAnnotationView *pinView = (MKAnnotationView*)[self.friendsMapView dequeueReusableAnnotationViewWithIdentifier:#"AnnotationIdentifier"];
if (!pinView)
{
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"AnnotationIdentifier"];
pinView.image = [UIImage imageNamed:#"mapann3.png"];
} else {
pinView.annotation = annotation;
}
pinView.canShowCallout = YES;
pinView.calloutOffset = CGPointMake(0, 0);
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mapann3.png"]];
pinView.leftCalloutAccessoryView = iconView;
return pinView;
}
return nil;
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
UITapGestureRecognizer *tapGesture2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(calloutTappedTwo:)];
[view addGestureRecognizer:tapGesture2];
}
-(void)calloutTappedTwo:(UITapGestureRecognizer *) sender
{
MKAnnotationView *view = (MKAnnotationView*)sender.view;
id <MKAnnotation> annotation = [view annotation];
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
PointAnnotation *selectedPoint = (PointAnnotation *) view.annotation;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
OtherUserViewController *yourViewController = (OtherUserViewController *)[storyboard instantiateViewControllerWithIdentifier:#"OtherUserViewController"];
NSMutableDictionary *dictionary = self.friendData[selectedPoint.index];
yourViewController.frienduserData = dictionary;
[self.navigationController pushViewController:yourViewController animated:YES];
}
}
That said, if I want a custom XIB I've created to appear as the callout when each annotation is tapped, where/how should I call this?

MapView: Tapping annotation gives me wrong detail view data?

I'm using an NSDictionary to populate data for my MapView annotations. However, when I tap on my MapView annotation, the detailView should display the selected user's information. That said, right now, when I tap an annotation, all detailViews display the same user's information (even though the details in the actual annotation's display bubble are correct). How can I fix this? Why won't NSDictionary allow me to do this?
MapViewController.m
NSMutableDictionary *viewParams = [NSMutableDictionary new];
[viewParams setValue:#"u000" forKey:#"view_name"];
[DIOSView viewGet:viewParams success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.addressData = [responseObject mutableCopy];
for (NSMutableDictionary *multiplelocations in self.addressData) {
NSString *location = multiplelocations[#"street_address"];
NSLog(#"Pull addresses %#", location);
NSString *userNames = multiplelocations[#"users_name"];
NSString *userBio = multiplelocations[#"userbio"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 8.0;
region.span.latitudeDelta /= 8.0;
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = placemark.coordinate;
point.title = userNames;
point.subtitle = userBio;
[self.mapView addAnnotation:point];
}
}
];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
}
-(void)calloutTapped:(UITapGestureRecognizer *) sender
{
NSLog(#"Callout was tapped");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
OtherUserViewController *yourViewController = (OtherUserViewController *)[storyboard instantiateViewControllerWithIdentifier:#"OtherUserViewController"];
NSDictionary *dictionary = [[NSDictionary alloc] init];
dictionary = [[self.addressData firstObject] mutableCopy];
yourViewController.mapuserData = dictionary;
[self.navigationController pushViewController:yourViewController animated:YES];
}
self.addressData via console
{
address = "1300 Fake Street, Vancouver, BC";
childrenunder = No;
city = Va;
"emergency facility" = Yes;
"first name" = Admin;
"last name" = Account;
phone = "Not Available";
"photo_path" = "http://myurl.com/files/stored/1461176121.jpg";
"postal code" = V6B0L1;
"profile photo" = "<img typeof=\"foaf:Image\" src=\"stored/1461176121.jpg\" width=\"300\" height=\"300\" alt=\"\" />";
"property type" = House;
province = B;
"street_address" = "1300 Fake Street, Vancouver, BC";
supervision = Yes;
uid = 1;
userbio = "Need assistance? This account belongs to the team! Message us if you have any questions.";
"users_name" = Britt;
}
)
dictionary = [[self.addressData firstObject] mutableCopy];
Are you serious?
This should be
NSMutableDictionary *dictionary = [self.addressData mutableCopy];
While navigating to detail view controller, you are always getting the first object from the dictionary array.
[[self.addressData firstObject] mutableCopy];
Thats the reason you are getting the same information for all the annotation view.
Instead of that line of code, You have to identify which map marker is clicked on the MapView, for example identify the index of the dictionary array. Pick the dictionary from the array and pass it to the detail view.

Loading online data very slow difficult to PUSH

First of all I am running a Map page that just only show pins on map for every store. I was running only one pin on the map and it was fast after I put more than 25 pins it push very slow to the map page. What it is doing now at that process the app just load all data of the pin location (as I see in the target output) and then it push to the next screen. So please where would be my problem?
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"";
self.navigationItem.title = #"Mek";
response = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://kalkatawi.com/mapLocation.php"]];
if(response!=nil) {
NSError *parseError = nil;
jsonArray = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:&parseError];
jsonArray1 = [[NSMutableArray alloc] init];
jsonArray2 = [[NSMutableArray alloc] init];
jsonArray3 = [[NSMutableArray alloc] init];
for(int i=0;i<[jsonArray count];i++)
{
name = [[jsonArray objectAtIndex:i] objectForKey:#"name"];
longitude = [[jsonArray objectAtIndex:i] objectForKey:#"longitude"];
latitude = [[jsonArray objectAtIndex:i] objectForKey:#"latitude"];
[jsonArray1 addObject:name];
[jsonArray2 addObject:longitude];
[jsonArray3 addObject:latitude];
self.locationMap.delegate = self; //set delegate before adding annotations
CLLocationCoordinate2D annotationCoord;
for (int i=0; i < [jsonArray count]; i++)
{
NSDictionary *annotationDictionary = [jsonArray objectAtIndex:i];
name = [annotationDictionary objectForKey:#"name"];
annotationCoord.latitude
= [[annotationDictionary objectForKey:#"longitude"] doubleValue];
annotationCoord.longitude
= [[annotationDictionary objectForKey:#"latitude"] doubleValue];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
annotationPoint.title = name;
annotationPoint.subtitle = [NSString stringWithFormat:#"%f %f", annotationPoint.coordinate.latitude, annotationPoint.coordinate.longitude];
[self.locationMap addAnnotation:annotationPoint];
//------------------------//
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(annotationPoint.coordinate, 50000, 50000);
[self.locationMap setRegion:[self.locationMap regionThatFits:region] animated:YES];
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
lat = locationManager.location.coordinate.latitude;
lon = locationManager.location.coordinate.longitude;
}
}
}
else {
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"You are not connected to internet" message:#"Please check the internet connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *pinView = nil;
if(annotation != locationMap.userLocation)
{
static NSString *defaultPinID = #"myPin";
pinView = (MKAnnotationView *)[locationMap dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinView.image = [UIImage imageNamed:#"pinpinpin.png"];
pinView.canShowCallout = YES;
pinView.enabled = YES;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.rightCalloutAccessoryView = infoButton;
}
return pinView;
}
SImple way is load data in background thread, and then when data is fully load display it on the map. You can do this in any of view controller, means you can do it in parent view controller and when you got response then update on map view controller.
Or on view did load method load data in background and update it when its load. This approach will not hold your UI. You can use blocks like this
dispatch_async(queue, ^{
//load data from server
dispatch_async(dispatch_get_main_queue(), ^{
//Update map
});
});

Draw polyline in mapview iOS 6

Hi I'm doing an app that must to show a map with the route. I parsed a Json to obtain the points to draw the polyline. I found a a code in the web to draw this polyline. The code I found it's on this link: http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/
Where it says "Create the MKPolyline annotation" I tried to import this in my app, but I'm having problems to create the array of the coordinates. My method is this:
- (void)createMKpolylineAnnotation {
NSInteger numberOfSteps = self.path.count;
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * numberOfSteps);
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [self.path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coords[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coords count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
When I try to look the value of coords is setted only the first time, why's that?
Can you help me to solve this problem or i should make in another mode?
I post here the code of the view controller that handle the map view.
MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic, strong) NSString *fromCity;
#property (nonatomic, strong) NSString *toCity;
- (IBAction)chooseKindOfMap:(id)sender;
#end
MapViewController.m
#import "MapViewController.h"
#import "AppDelegate.h"
#import "PlaceAnnotation.h"
#interface MapViewController ()
#property (nonatomic, strong)NSMutableArray *mapAnnotation;
#property (nonatomic) BOOL needUpdateRegion;
#property (nonatomic, strong)NSMutableArray *path;
#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 parseGoogleJsonToObtainPointsForPolyline];
[self.mapView setDelegate:self];
self.needUpdateRegion = YES;
//[self centerMap];
self.mapAnnotation = [[NSMutableArray alloc]initWithCapacity:2];
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
NSLog(#"%d", appDelegate.dataForMap.count);
NSArray* coords = [self getCoords:appDelegate.dataForMap];
NSLog(#"coords = %#", coords);
PlaceAnnotation *fromPlace = [[PlaceAnnotation alloc] initWithCoordinateAndName:coords[0] andLong:coords[1] andName:self.fromCity];
PlaceAnnotation *toPlace = [[PlaceAnnotation alloc] initWithCoordinateAndName:coords[2] andLong:coords[3] andName:self.toCity];
[self.mapAnnotation insertObject:fromPlace atIndex:0];
[self.mapAnnotation insertObject:toPlace atIndex:1];
NSLog(#"mapAnnotation.count: %d", self.mapAnnotation.count);
if (self.mapAnnotation) {
[self.mapView removeAnnotations:self.mapView.annotations];
}
[self.mapView addAnnotation:self.mapAnnotation[0]];
[self.mapView addAnnotation:self.mapAnnotation[1]];
NSLog(#"MapAnnotation = %#", self.mapView.annotations);
[self updateRegion];
[self createMKpolylineAnnotation];
}
//- (void)viewDidAppear:(BOOL)animated {
// [super viewDidAppear:animated];
// if (self.needUpdateRegion) [self updateRegion];
//}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
MKPinAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
pin.pinColor = MKPinAnnotationColorRed;
return pin;
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKPinAnnotationView *ulv = [mapView viewForAnnotation:mapView.userLocation];
ulv.hidden = YES;
}
- (NSArray*)getCoords:(NSDictionary*)data {
NSArray *legs = [data objectForKey:#"legs"];
NSDictionary *firstZero = [legs objectAtIndex:0];
NSDictionary *endLocation = [firstZero objectForKey:#"end_location"];
NSDictionary *startLocation = [firstZero objectForKey:#"start_location"];
NSString *latFrom = [startLocation objectForKey:#"lat"];
NSString *lngFrom = [startLocation objectForKey:#"lng"];
NSString *latTo = [endLocation objectForKey:#"lat"];
NSString *lngTo = [endLocation objectForKey:#"lng"];
return #[latFrom,lngFrom,latTo,lngTo];
}
- (void)centerMap {
MKCoordinateRegion region;
region.center.latitude = 41.178654;
region.center.longitude = 11.843262;
region.span.latitudeDelta = 11.070406;
region.span.longitudeDelta = 12.744629;
[self.mapView setRegion:region];
}
- (IBAction)chooseKindOfMap:(id)sender {
if ([sender tag] == 0) {
self.mapView.mapType = MKMapTypeStandard;
}
if ([sender tag] == 1) {
self.mapView.mapType = MKMapTypeSatellite;
}
if ([sender tag] == 2) {
self.mapView.mapType = MKMapTypeHybrid;
}
}
- (void)updateRegion
{
self.needUpdateRegion = NO;
CGRect boundingRect;
BOOL started = NO;
for (id <MKAnnotation> annotation in self.mapView.annotations) {
CGRect annotationRect = CGRectMake(annotation.coordinate.latitude, annotation.coordinate.longitude, 0, 0);
if (!started) {
started = YES;
boundingRect = annotationRect;
} else {
boundingRect = CGRectUnion(boundingRect, annotationRect);
}
}
if (started) {
boundingRect = CGRectInset(boundingRect, -0.2, -0.2);
if ((boundingRect.size.width < 20) && (boundingRect.size.height < 20)) {
MKCoordinateRegion region;
region.center.latitude = boundingRect.origin.x + boundingRect.size.width / 2;
region.center.longitude = boundingRect.origin.y + boundingRect.size.height / 2;
region.span.latitudeDelta = boundingRect.size.width;
region.span.longitudeDelta = boundingRect.size.height;
[self.mapView setRegion:region animated:YES];
}
}
}
- (void)parseGoogleJsonToObtainPointsForPolyline {
NSDictionary *polyline;
NSMutableArray *points = [[NSMutableArray alloc]init];;
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
NSArray *legs = [appDelegate.dataForMap objectForKey:#"legs"];
NSDictionary *firstZero =[legs objectAtIndex:0];
NSArray *steps = [firstZero objectForKey:#"steps"];
for (int i = 0; i < steps.count; i++) {
polyline = [steps[i] objectForKey:#"polyline"];
[points addObject:polyline[#"points"]];
NSLog(#"POINTS = %#", polyline[#"points"]);
self.path = [self decodePolyLine:points[i]];
}
NSLog(#"path = %#", self.path);
}
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor redColor];
polylineView.lineWidth = 1.0;
return polylineView;
}
- (void)createMKpolylineAnnotation {
NSInteger numberOfSteps = self.path.count;
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * numberOfSteps);
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [self.path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coords[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coords count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
#end
I used the AppDelegate to have the Json (I parsed it in another class)
Here is a tutorial how to add a polyline to a mapView. Hope this helps!
EDIT:
Unfortunately, the link provided above is now broken, and I am not able to find the tutorial referred to.
simple, just copy and paste my code and modify some variables
- (IBAction)traceRoute:(UIButton *)sender {
double latDouble = 39.7540615;
double lngDouble = -8.8059587;
// double latDouble = [self.sheetDetail.data.locationLat doubleValue];
// double lngDouble = [self.sheetDetail.data.locationLng doubleValue];
CLLocationCoordinate2D c2D = CLLocationCoordinate2DMake(latDouble, lngDouble);
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:c2D addressDictionary:nil];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:#"Mobile Edge"];
MKPlacemark *placemark2;
MKMapItem *mapItem2;
if(kIS_OS_8_OR_LATER) {
placemark2 = [[MKPlacemark alloc] initWithCoordinate:_userLoc addressDictionary:nil];
mapItem2 = [[MKMapItem alloc] initWithPlacemark:placemark2];
[mapItem2 setName:#"Me"];
} else {
placemark2 = [[MKPlacemark alloc] initWithCoordinate:_mapView.userLocation.coordinate addressDictionary:nil];
mapItem2 = [[MKMapItem alloc] initWithPlacemark:placemark2];
[mapItem2 setName:#"Me"];
}
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = mapItem2;
request.destination = mapItem;
request.requestsAlternateRoutes = NO;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
[[NSNotificationCenter defaultCenter] postNotificationName:#"finishedLocationRoute" object:nil];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: NSLocalizedString(#"Route error title", nil)
message: NSLocalizedString(#"Route error", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
} else {
for (MKRoute *route in response.routes)
{
//MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
//[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint) andRoute:route];
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
//notifies parent menu
//[[NSNotificationCenter defaultCenter] postNotificationName:#"finishedLocationRoute" object:nil];
}
}];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay
{
if (![overlay isKindOfClass:[MKPolygon class]]) {
MKPolyline *route = overlay;
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
renderer.strokeColor = [UIColor blueColor];
renderer.lineWidth = 5.0;
return renderer;
} else {
return nil;
}
}

Trying to Get Current Location integrated with iOS project

So I'm attempting to integrate the user's current location with my iOS project - I'm using some third part code to build out the map with the pinpoints - I have these frameworks integrated:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <QuartzCore/QuartzCore.h>
#import <MapKit/MapKit.h>
here's my code with the pinpoints - any help would be greatly appreciated:
#import "asyMap.h"
#implementation asyMap
#synthesize currentAnnotation,mapAnnotations,map,prompt,mapFromLink,selectedAnnotationId,selectedAnnotationIndex,showOthers,useCustomTitle,customTitle;
/**
* Class constructor
*/
-(id)init{
self = [super init];
if(self){
useCustomTitle = FALSE;
mapFromLink = FALSE;
showOthers = FALSE;
map = [[asyMapObject alloc] init];
[map addOnView:self.view];
}
return self;
}
/**
* Overwrite the set page method in
* order to show a selected annotation
* from a link
*/
-(void)setPage:(NSDictionary *)page{
NSDictionary *metas = [page valueForKey:#"metas"];
if([metas valueForKey:#"selectedAnnotationPageTitle"] && ![[[metas valueForKey:#"selectedAnnotationPageTitle"] stringValue] isEqualToString:#""] && customTitle == nil){
useCustomTitle = TRUE;
NSString *newTitle = [metas valueForKey:#"selectedAnnotationPageTitle"];
customTitle = [[NSString alloc] initWithString:[[newTitle stringByReplacingOccurrencesOfString:#"+" withString:#" "] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
if(useCustomTitle && customTitle != nil){
NSMutableDictionary *pageWithCustomTitle = [[NSMutableDictionary alloc] initWithDictionary:page];
[pageWithCustomTitle setValue:customTitle forKey:#"title"];
[super
setPage:pageWithCustomTitle];
}else{
[super setPage:page];
}
if([metas valueForKey:#"annotationFromLink"] && [[[metas valueForKey:#"annotationFromLink"] stringValue] isEqualToString:#"yes"] && selectedAnnotationId == nil){
selectedAnnotationId = [[NSString alloc] initWithString:[metas valueForKey:#"selectedAnnotation"]];
mapFromLink = TRUE;
showOthers = [[[metas valueForKey:#"showOthers"] stringValue] isEqualToString:#"yes"];
}else if(mapFromLink && selectedAnnotationId != nil){
mapFromLink = FALSE;
NSArray *annotations = [page valueForKey:#"annotations"];
for(int a = 0; a < [annotations count]; a++){
NSDictionary *annotation = [annotations objectAtIndex:a];
if([[[annotation valueForKey:#"annotationId"] stringValue] isEqualToString:selectedAnnotationId]){
mapFromLink = TRUE;
selectedAnnotationIndex = a;
break;
}
}
}
}
/**
* Set the module's name
*/
-(void)makeProcess{
[self setModuleName:#"map"];
}
/**
* Create the basic prompt alert
*/
-(void)buildModule{
prompt = [[UIAlertView alloc] initWithTitle:#"" message:[theme asy__:#"Open on the Maps app?"] delegate:self cancelButtonTitle:[theme asy__:#"No"] otherButtonTitles:[theme asy__:#"Yes"], nil];
}
/**
* Set the annotations after get the page data
*/
-(void)requestedPage:(NSDictionary *)pageInformation{
[self setPage:pageInformation];
if(mapFromLink && !showOthers && [[self getPageMapAnnotations] count] > 0){
NSArray *pageAnnotations = [self getPageMapAnnotations];
mapAnnotations = [[NSArray alloc] initWithObjects:[pageAnnotations objectAtIndex:selectedAnnotationIndex],nil];
}else{
mapAnnotations = [[NSArray alloc] initWithArray:[self getPageMapAnnotations]];
}
[map setMapAnnotations:mapAnnotations andDelegate:self];
if(mapFromLink){
[map focusMapOnAnnotationAtIndex:(showOthers ? selectedAnnotationIndex : 0)];
}
[map build];
[self hideLoading];
[self checkPageOptionButton];
}
/**
* The module orientation did change
*/
-(void)moduleOrientationDidChange{
[map setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}
#pragma mark - Map Delegate
/**
* Check if the annotation has properties for action or the prompt to be opened
* on the Maps app should appear
*/
-(void)asyMapObject:(asyMapObject *)mapObject didSelectAnnotation:(NSDictionary *)annotation atIndex:(NSInteger)index{
currentAnnotation = index;
if([[annotation valueForKey:#"menuId"] isEqualToString:#"0"] &&
[[annotation valueForKey:#"pageId"] isEqualToString:#"0"] &&
[[annotation valueForKey:#"link"] isEqualToString:#""] &&
[[annotation valueForKey:#"url"] isEqualToString:#""] &&
[[annotation valueForKey:#"phpfile"] isEqualToString:#""]){
[prompt setTitle:[annotation valueForKey:#"title"]];
[prompt show];
}else{
AppsifymeCore *core = [AppsifymeCore sharedAppsifymeCore];
[core basicHandlerForMultiActionsOption:annotation];
}
}
#pragma mark - Alert view delegate
/**
* Detect if the user wants to open the annotation on the maps app, and if its
* true, this method build the link and open the app
*/
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex != 1) return;
AppsifymeCore *core = [AppsifymeCore sharedAppsifymeCore];
NSDictionary *annotation = [mapAnnotations objectAtIndex:currentAnnotation];
float latitude = [[annotation valueForKey:#"latitude"] floatValue];
float longitude = [[annotation valueForKey:#"longitude"] floatValue];
if(![core asyiOS6]){
NSString *pinName = [[NSString alloc] initWithString:[core encodeURLParameter:[annotation valueForKey:#"title"]]];
int zoom = 13;
NSString *stringURL = [[NSString alloc] initWithFormat:#"http://maps.apple.com/maps?q=%##%1.6f,%1.6f&z=%d", pinName, latitude, longitude, zoom];
NSURL *url = [[NSURL alloc] initWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];
}else{
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude,longitude);
MKPlacemark *placeMark = [[MKPlacemark alloc] initWithCoordinate:coordinate addressDictionary:nil];
MKMapItem *item = [[MKMapItem alloc] initWithPlacemark:placeMark];
item.name = [[annotation valueForKey:#"title"] stringValue];
[item openInMapsWithLaunchOptions:nil];
}
}
}
#end
In your init method, add this line
self.showsUserLocation = YES;

Resources