Набор карт iOS 8 Obj-C не может найти пользователей

Я работаю с Map Kit в iOS 8, используя Obj-C, а не SWIFT. Я не могу определить местоположение устройства, для него установлено 0,00, 0,00, и я получаю сообщение об ошибке:

Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.

Я реализовал: (Я попробовал только один за раз, и не повезло)

if(IS_OS_8_OR_LATER) {
    [self.locationManager requestWhenInUseAuthorization];
    [self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation]; 

И в info.plist

NSLocationWhenInUseUsageDescription  :   App would like to use your location.
NSLocationAlwaysUsageDescription  :  App would like to use your location.

Я получаю приглашение разрешить приложению использовать мое местоположение, но после того, как я согласен, ничего не меняется. Местоположение показывается как 0,00, 0,00.

Код для отображения местоположения пользователя:

//Get Location
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];

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];

Майк.

** РЕДАКТИРОВАТЬ: Просмотреть ответ ниже.

8 ответов

Решение

Я получил это работает. Я разместил свой код ниже, чтобы помочь другим людям, имеющим проблемы.

Вот мой полный код, чтобы заставить MapKit Map View работать в iOS 8.

В вашем AppName-Info.plist добавьте новую строку с именем ключа:

NSLocationWhenInUseUsageDescription

Или же

NSLocationAlwaysUsageDescription

Со значением, являющимся строкой сообщения, которое вы хотите отобразить:

YourAppName would like to use your location.

В вашем заголовочном файле. (Я использую имя приложения-Prefix.pch, но YourViewController.h тоже будет работать)

#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];
}

Наслаждайтесь!

--Майк

Он нигде не написан, но если ваше приложение запускается с MapKit, вы по-прежнему будете получать сообщение об ошибке "Попытка запуска обновлений местоположения MapKit без запроса авторизации местоположения" даже после реализации ответа MBarton. Чтобы избежать этого, вы должны создать новый контроллер представления перед MapKit и внедрить туда делегаты менеджера расположений. Я назвал это AuthorizationController.

Итак, в AuthorizationController.h:

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

@interface MCIAuthorizationController : UIViewController <CLLocationManagerDelegate>

@property (strong, nonatomic) CLLocationManager *locationManager;

@end

И в AuthorizationController.m:

- (void)viewDidLoad {
    [super viewDidLoad];

    // Location manager
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;

    // Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
    if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
        [self.locationManager requestWhenInUseAuthorization];
    }
}

#pragma mark - Location Manager delegates

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    NSLog(@"didUpdateLocations: %@", [locations lastObject]);
}


- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"Location manager error: %@", error.localizedDescription);
}

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
        [self.locationManager startUpdatingLocation];
        [self performSegueWithIdentifier:@"startSegue" sender:self];
    } else if (status == kCLAuthorizationStatusDenied) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Location services not authorized"
                                                        message:@"This app needs you to authorize locations services to work."
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
        [alert show];
    } else
        NSLog(@"Wrong location status");
}

Попробуй это:

 (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {

    if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
        self.mapView.showsUserLocation = YES;
    }

У меня была такая же проблема, но добавление этих двух строк в файл plist решило мои проблемы

NSLocationWhenInUseUsageDescription

А также

NSLocationAlwaysUsageDescription

ПРИМЕЧАНИЕ. Необходимо предоставить строковое описание обоих этих значений. Вы можете использовать любой из них в вашем файле контроллера, как показано ниже

self.locationManager= [[CLLocationManager alloc] init];
self.locationManager.delegate=self;
[self.locationManager requestAlwaysAuthorization];

Вы должны реализовать CLLOcationManagerDelegate в вашем контроллере для доступа к этой функции

Ваш код выглядит нормально, хотя вам не нужно вызывать requestWhenInUseAuthorization, а другой запрос всегда разрешает, выберите тот, который вам нужен.

Код для отображения местоположений еще только распределяет locationManager, не ожидайте мгновенного получения данных о местоположении.

вам нужно подождать, пока будет вызван метод делегата: -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
, тогда также будет установлен self.locationManager.location.

В дополнение к ответу Майка, я обнаружил, что используя оба [self.locationManager requestWhenInUseAuthorization]; а также [self.locationManager requestAlwaysAuthorization]; как показано в его коде не работает. Вы должны использовать только ОДИН.

Я предполагаю, что некоторые дальнейшие изменения были внесены в более свежую / стабильную версию API.

Чтобы расширить принятый ответ, и если вы создаете пример проекта только с вышеуказанными функциями, то кроме CoreLocation а также Mapkit рамки, вам может понадобиться добавить UIKit, Foundation а также CoreGraphics рамки вручную, а также в Xcode 6,

На самом деле, я изучаю лекцию CS193P 16, посвященную местоположению и представлению карты, и я не смог заставить диспетчер местоположения работать в iOS 8, применяя то, что было в видео. Глядя на ваш ответ, я мог бы заставить его работать.

Info.plist был изменен, как описано в ответах (я использую NSLocationWhenInUseUsageDescription).

В AddPhotoViewController.hn было добавлено определение:

#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

В AddPhotoViewController.m следующий код был добавлен в ViewDidLoad (после self.image):

#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER)
{
    [self.locationManager requestWhenInUseAuthorization];
}
#endif

Авторизация будет запрошена только один раз, при первом запуске приложения.

Следующее также было добавлено в AddPhotoViewController.h, потому что это не было сказано в лекции 16:

@property (nonatomic) NSInteger locationErrorCode;

shouldPerformSegueWithIdentifier был изменен, чтобы включить else if (! self.location):

else if (![self.titleTextField.text length])
        {
            [self alert:@"Title required"];
            return NO;
        }
        else if (!self.location)
        {
            switch (self.locationErrorCode)
            {
                case kCLErrorLocationUnknown:
                    [self alert:@"Couldn't figure out where this photo was taken (yet)."]; break;
                case kCLErrorDenied:
                    [self alert:@"Location Services disabled under Privacy in Settings application."]; break;
                case kCLErrorNetwork:
                    [self alert:@"Can't figure out where this photo is being taken.  Verify your connection to the network."]; break;
                default:
                    [self alert:@"Cant figure out where this photo is being taken, sorry."]; break;
            }
            return NO;
        }
        else
        { // should check imageURL too to be sure we could write the file
            return YES;
        }

didFailWithError был добавлен:

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    self.locationErrorCode = error.code;
}
Другие вопросы по тегам