I am trying to get the Map Kit to display the current user's location down to a predefined size.
Everything was working but since updating to Xcode 6 and iOS 8, things have changed.
I have implemented the necessary authorizations and now the app crashes. The code with *** is the code that the system seems to have a problem with.
Here is Map.m
#import "MRVCMapViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import CoreLocation;
#interface MRVCMapViewController ()
#end
#implementation MRVCMapViewController
#synthesize mapView;
- (void)viewDidLoad {
[super viewDidLoad];
//location permission
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
//mapview settings
self.mapView.delegate = self;
self.mapView.showsUserLocation = YES;
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
***MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];***
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You haven't checked that the userLocation value is valid. You should make sure it is not nil before trying to use it for anything.
Related
i got this error what that error meant to be.i can't understand what error it is.
so plz help
thanks
error
1.ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController<MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mycurrentlocation;
#end
2. ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController #synthesize mycurrentlocation;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mycurrentlocation.delegate = self; }
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated. }
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
MKCoordinateRegion re = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800,
800);
[self.mycurrentlocation setRegion:[self.mycurrentlocation regionThatFits:re] animated:YES];
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = userLocation.coordinate;
point.title = #"Where am I?";
point.subtitle = #"I'm here!!!";
[self.mycurrentlocation addAnnotation:point]; }
#end
Then put this line of code in the viewDidLoad method of your class:
[self.locationManager requestAlwaysAuthorization];
You need to add the core location framework and Map Kit framework.
In your AppName-Info.plist Add a new row with the key name being:
NSLocationWhenInUseUsageDescription
Or
NSLocationAlwaysUsageDescription
With the value being a string of the message that you want to be displayed:
YourAppName would like to use your location.
In your header file. (I use App Name-Prefix.pch but YourViewController.h will work too)
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
YourViewController.h
#import <MapKit/MapKit.h>
#import <MapKit/MKAnnotation.h>
#interface YourViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate> {
}
#property(nonatomic, retain) IBOutlet MKMapView *mapView;
#property(nonatomic, retain) CLLocationManager *locationManager;
YourViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
mapView.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER) {
// Use one or the other, not both. Depending on what you put in info.plist
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
#endif
[self.locationManager startUpdatingLocation];
mapView.showsUserLocation = YES;
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
NSLog(#"%#", [self deviceLocation]);
//View Area
MKCoordinateRegion region = { { 0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = self.locationManager.location.coordinate.latitude;
region.center.longitude = self.locationManager.location.coordinate.longitude;
region.span.longitudeDelta = 0.005f;
region.span.longitudeDelta = 0.005f;
[mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
- (NSString *)deviceLocation {
return [NSString stringWithFormat:#"latitude: %f longitude: %f", self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceLat {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.latitude];
}
- (NSString *)deviceLon {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceAlt {
return [NSString stringWithFormat:#"%f", self.locationManager.location.altitude];
}
Getting the user location to work has been killing me...
I've read lots of threads explaining the new changes with iOS 8 and how there must be one of two keys (NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription) in the info.plist file in order for the app to ask permission to get user location. I did that.
I've also included what I believe as all the code needed for the location service to work...but it doesn't. Please see my mapViewController.h and mapViewController.m files below:
mapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <MapKit/MKAnnotation.h>
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
#interface mapViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>
#property(nonatomic, retain) IBOutlet MKMapView *mapView;
#property(nonatomic, retain) CLLocationManager *locationManager;
#end
mapViewController.m
#import "mapViewController.h"
#interface mapViewController ()
#end
#implementation mapViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.mapView.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER) {
// Use one or the other, not both. Depending on what you put in info.plist
//[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
#endif
[self.locationManager startUpdatingLocation];
self.mapView.showsUserLocation = YES;
[self.mapView setMapType:MKMapTypeStandard];
[self.mapView setZoomEnabled:YES];
[self.mapView setScrollEnabled:YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
self.locationManager.distanceFilter = kCLDistanceFilterNone; //Whenever we move
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
NSLog(#"%#", [self deviceLocation]);
//View Area
MKCoordinateRegion region = { { 0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = self.locationManager.location.coordinate.latitude;
region.center.longitude = self.locationManager.location.coordinate.longitude;
region.span.longitudeDelta = 0.005f;
region.span.longitudeDelta = 0.005f;
[self.mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
- (NSString *)deviceLocation {
return [NSString stringWithFormat:#"latitude: %f longitude: %f", self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceLat {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.latitude];
}
- (NSString *)deviceLon {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceAlt {
return [NSString stringWithFormat:#"%f", self.locationManager.location.altitude];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Also, in case this is relevant, the mapViewController is tied to a tab in a Tab View Controller. When I click on the tab that includes the view controller containing MKMapView, I get the below image:
Use this code and run the application in device to get the current location.
If you run in simulator, then it will show the default location i.e Apple Inc's address as current location.
- (void)viewDidLoad
{
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager setDelegate:self ];
self.mapView.showsUserLocation=YES;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation: (CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[self.mapView setCenterCoordinate:newLocation.coordinate animated:YES];
MKCoordinateRegion region=MKCoordinateRegionMakeWithDistance(newLocation.coordinate,70000 ,70000 );
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits:region];
[self.mapView setRegion:adjustedRegion animated:YES];
}
Note:
Turn on data or wifi in your device, or else you will face Location Accuracy error.
Add the below code to your ViewController.h class,
#interface ViewController : UIViewController<CLLocationManagerDelegate>
#property(nonatomic, retain) CLLocationManager *locationManager;
#end
And in ViewController.m class ,
-(void)viewWillAppear:(BOOL)animated{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
[super viewWillAppear:animated];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D zoomLocation = CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude);
}
Per the docs, [self.locationManager requestAlwaysAuthorization] is asynchronous. Implement the location services auth changed delegate callback and start monitoring there only after the auth status is allowed.
I am building an iOS application that display a POI in a MapView, but firstly I can display the map, and with iOS8 this is begin a problem.
I read a lot question in this site, but none run on my app even if the code seems right.
I entered into myapplicationTest-info.plist the following code
<key>NSLocationAlwaysUsageDescription</key>
And the code in the file.m is this:
#import "MapViewController.h"
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
#interface MapViewController ()
#end
#implementation MapViewController
#synthesize mapView = _mapView ;
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
self.locationManager.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
if (IS_OS_8_OR_LATER) {
//[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
self.mapView.showsUserLocation = YES;
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
self.locationManager.distanceFilter = kCLDistanceFilterNone; //Whenever we move
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
NSLog(#"%#", [self deviceLocation]);
//View Area
MKCoordinateRegion region = { { 0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = self.locationManager.location.coordinate.latitude;
region.center.longitude = self.locationManager.location.coordinate.longitude;
region.span.longitudeDelta = 0.005f;
region.span.longitudeDelta = 0.005f;
[mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
- (NSString *)deviceLocation {
return [NSString stringWithFormat:#"latitude: %f longitude: %f", self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceLat {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.latitude];
}
- (NSString *)deviceLon {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceAlt {
return [NSString stringWithFormat:#"%f", self.locationManager.location.altitude];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Where is the mistake?
Why it doesn't run?
You need to provide a value for NSLocationAlwaysUsageDescription key which is the string that describes why your app wants to use location services -
For example -
<key>NSLocationAlwaysUsageDescription</key>
<string>FindMeDonuts will use your location to identify nearby donut shops</string>
Also, rather than checking the iOS version, it is better to check if CLLocationManager responds to the authorisation selector -
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
finally, this won't stop your map from updating, but it doesn't make sense - you are assigning a delegate to your CLLocationManager before you allocate and initialise it.
You should say -
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate=self;
I don't know if i understand your problem.
if your problem is about the map is not show, you need to set frame of your map.
self.mapView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
hope i could help you
The best way is to use the -locationManager:didUpdateLocations method provided by CLLocationManagerDelegate.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
[self.locationManager stopUpdatingLocation];
// Move this line here
self.mapView.showsUserLocation = YES;
}
After calling [self.locationManager startUpdatingLocation] in ViewDidLoad, you shouldn't set self.mapView.showsUserLocation to YES yet as permission to use location services is not yet approved. Use the delegate to wait/get a location update from the system before setting self.mapView.showsUserLocation to YES.
You also need to enable location services
if([CLLocationManager resolveClassMethod:#selector(locationServicesEnabled)]) {
[CLLocationManager locationServicesEnabled];
}
I am going through a tutorial on youtube that teaches you how to track and trace a user's location on a map view. The tutorial comes with a copy of the code so I downloaded the code files and opened them up in Xcode. The first time that I opened the code in Xcode I had the newest Xcode 5. It ran just fine finding and tracing the location. About a day later Xcode 6 came out so I updated my Xcode to Xcode 6. When opening the code files in Xcode 6, the application would not preform correctly. I am getting an error that says...
2014-09-28 17:24:34.468 GPSTrack[1644:130866] Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
In the header file GPSTrackerViewController.h
//
// GPSTrackViewController.h
// GPSTrack
//
// Created by Nick Barrowclough on 4/21/14.
// Copyright (c) 2014 iSoftware Developers. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h> //import the mapkit framework
#interface GPSTrackViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate, MKOverlay> {
CLLocationManager *lm; //core lcoation manager instance
NSMutableArray *trackPointArray; //Array to store location points
//instaces from mapkit to draw trail on map
MKMapRect routeRect;
MKPolylineView* routeLineView;
MKPolyline* routeLine;
}
- (IBAction)startTracking:(id)sender;
- (IBAction)stopTracking:(id)sender;
- (IBAction)clearTrack:(id)sender;
#property (weak, nonatomic) IBOutlet MKMapView *mapview;
#end
GPSTrackViewController.m
//
// GPSTrackViewController.m
// GPSTrack
//
// Created by Nick Barrowclough on 4/21/14.
// Copyright (c) 2014 iSoftware Developers. All rights reserved.
//
#import "GPSTrackViewController.h"
#interface GPSTrackViewController ()
#end
#implementation GPSTrackViewController
#synthesize mapview;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
mapview.mapType = MKMapTypeHybrid;
}
- (void)viewWillAppear:(BOOL)animated {
trackPointArray = [[NSMutableArray alloc] init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startTracking:(id)sender {
//start location manager
lm = [[CLLocationManager alloc] init];
lm.delegate = self;
lm.desiredAccuracy = kCLLocationAccuracyBest;
lm.distanceFilter = kCLDistanceFilterNone;
[lm startUpdatingLocation];
mapview.delegate = self;
mapview.showsUserLocation = YES;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
//get the latest location
CLLocation *currentLocation = [locations lastObject];
//store latest location in stored track array;
[trackPointArray addObject:currentLocation];
//get latest location coordinates
CLLocationDegrees Latitude = currentLocation.coordinate.latitude;
CLLocationDegrees Longitude = currentLocation.coordinate.longitude;
CLLocationCoordinate2D locationCoordinates = CLLocationCoordinate2DMake(Latitude, Longitude);
//zoom map to show users location
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(locationCoordinates, 1000, 1000);
MKCoordinateRegion adjustedRegion = [mapview regionThatFits:viewRegion]; [mapview setRegion:adjustedRegion animated:YES];
NSInteger numberOfSteps = trackPointArray.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [trackPointArray objectAtIndex:index];
CLLocationCoordinate2D coordinate2 = location.coordinate;
coordinates[index] = coordinate2;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[mapview addOverlay:polyLine];
//NSLog(#"%#", trackPointArray);
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor redColor];
polylineView.lineWidth = 4.0;
return polylineView;
}
- (IBAction)stopTracking:(id)sender {
//reset location manager and turn off GPS
lm = [[CLLocationManager alloc] init];
[lm stopUpdatingLocation];
lm = nil;
//stop shwing user location
mapview.showsUserLocation = NO;
//reset array fo tracks
trackPointArray = nil;
trackPointArray = [[NSMutableArray alloc] init];
}
- (IBAction)clearTrack:(id)sender {
//remove overlay on mapview
[mapview removeOverlays: mapview.overlays];
}
#end
Can someone please help me understand why the application is not running any more and give me some suggestions of what I need to do to get it up and running again.
under base sdk 8 (which is what xcode 6 uses, I removed the xcode tag as it isn't IDE specific) you have to ask for authorisation first and have to have a plist key (a string saying why you need to use GPS)
the plist key depends on your needs is EITHER
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
this SO question looks good:
IOS 8 CLLocationManager Issue (Authorization Not Working)
for detailed instructs, I can recommend (skimmed it):
http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/
I can't understand how CLLocationManager get my current location coordinates ? if I don't call [locationManager startUpdatingLocation] and don't set parameters in locationManager.location.coordinate.
ViewController.h
#interface ViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
}
#property (weak, nonatomic) IBOutlet MKMapView* mapView;
#end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
[self.mapView setShowsUserLocation:YES];
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
}
-(void) mapView:(MKMapView *) mv didAddAnnotationViews:(NSArray *)views {
MKCoordinateRegion region;
region = MKCoordinateRegionMakeWithDistance(locationManager.location.coordinate, 1000, 1000);
[mv setRegion:region animated:YES];
}
Most likely it's a cached value after MapView requested current location update because of the following line:
[self.mapView setShowsUserLocation:YES];