Когда пользователь неподвижен: после вызова startUpdatingHeading() объект CLHeading, возвращаемый в обратном вызове locationManager(_:didUpdateHeading:), правильно отражает фактическое физическое состояние устройства ориентация (т. е. направление, куда указывает верхняя часть устройства) с точки зрения магнитного севера/истинного севера с помощью свойств MagneticHeading и trueHeading. Когда я поворачиваю устройство, значения заголовка соответственно изменяются — это ожидаемое поведение.
Но когда пользователь находится в движении (например, за рулем автомобиля): даже если я поворачиваю устройство, значения MagneticHeading и trueHeading больше не отражают фактическую ориентацию устройства. Вместо этого они последовательно возвращают то, что выглядит как направление движения пользователя или транспортного средства (направление вперед). Другими словами, компас ведет себя так, как будто он сообщает направление движения, а не фактическое направление взгляда устройства.
Только после того, как пользователь полностью прекратил движение, вращение устройства снова приводит к тому, что MagneticHeading и trueHeading отражают фактическую ориентацию устройства, как ожидалось.
Однако на другом устройстве под управлением iOS 16 (iPhone XR) такого поведения не происходит — все работает обычно.
Ожидаемое поведение
Я ожидаю, что независимо от того, движется пользователь или нет, значения CLHeading, возвращаемые CLLocationManager, всегда должны отражать физическую ориентацию самого устройства (т. е. в каком направлении указывает верхняя часть устройства), как и должен делать стандартный компас.
Фактическое Поведение
Пользователь неподвижен, вращает устройство: MagneticHeading / trueHeading изменяется должным образом в соответствии с фактической ориентацией устройства.
Пользователь находится в движении (например, за рулем):
Код: Выделить всё
magneticHeadingПользователь прекращает движение, а затем поворачивает устройство: Компас снова ведет себя нормально, отражая фактическую ориентацию устройства.
Информация об окружающей среде
Версия iOS: iOS 26.0.1
Модели устройств: iPhone 15 Pro / iPhone 17 Про
Версия Xcode: Xcode 26.0.1
Язык: Objective-C
минимальный воспроизводимый пример:
Код: Выделить всё
#import
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIView *compass;
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, strong) UILabel *labelInfo;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self checkAndRequestLocationPermission:self.locationManager.authorizationStatus];
self.labelInfo = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 200)];
self.labelInfo.textColor = [UIColor systemBlueColor];
self.labelInfo.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:self.labelInfo];
self.compass = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
self.compass.backgroundColor = [UIColor systemGrayColor];
self.compass.center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds));
[self.view addSubview:self.compass];
UILabel *label_N = [[UILabel alloc] initWithFrame:CGRectMake(35, 0, 30, 30)];
label_N.text = @"N";
label_N.textAlignment = NSTextAlignmentCenter;
label_N.textColor = [UIColor systemRedColor];
UILabel *label_S = [[UILabel alloc] initWithFrame:CGRectMake(35, 70, 30, 30)];
label_S.text = @"S";
label_S.textAlignment = NSTextAlignmentCenter;
UILabel *label_W = [[UILabel alloc] initWithFrame:CGRectMake(0, 35, 30, 30)];
label_W.text = @"W";
label_W.textAlignment = NSTextAlignmentCenter;
UILabel *label_E = [[UILabel alloc] initWithFrame:CGRectMake(70, 35, 30, 30)];
label_E.text = @"E";
label_E.textAlignment = NSTextAlignmentCenter;
[self.compass addSubview:label_N];
[self.compass addSubview:label_S];
[self.compass addSubview:label_W];
[self.compass addSubview:label_E];
}
- (void)startUpdatingLocation {
[self.locationManager startUpdatingLocation];
[self startUpdatingHeading];
}
- (void)startUpdatingHeading {
if ([CLLocationManager headingAvailable]) {
self.locationManager.headingFilter = 3;
[self.locationManager startUpdatingHeading];
} else {
NSLog(@"The device does not support ");
}
}
- (void)checkAndRequestLocationPermission:(CLAuthorizationStatus)status {
switch (status) {
case kCLAuthorizationStatusNotDetermined:
[self.locationManager requestWhenInUseAuthorization];
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
case kCLAuthorizationStatusAuthorizedAlways:
[self startUpdatingLocation];
break;
case kCLAuthorizationStatusDenied:
case kCLAuthorizationStatusRestricted:
break;
default:
break;
}
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{
if (newHeading.headingAccuracy < 0){
return;
}
CGFloat degrees = newHeading.trueHeading;
self.compass.transform = CGAffineTransformMakeRotation(-(degrees * M_PI / 180.0));
}
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
CLAuthorizationStatus status = manager.authorizationStatus;
[self checkAndRequestLocationPermission:status];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations lastObject];
CLLocationSpeed speed = location.speed;
if (speed > 0) {
self.labelInfo.text = [NSString stringWithFormat:@"%.2f km/h", speed * 3.6];
} else {
self.labelInfo.text = @"Stationary";
}
NSLog(@"location - lat: %f, lng: %f",
location.coordinate.latitude,
location.coordinate.longitude);
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
NSLog(@"Fail: %@", error.localizedDescription);
}
@end
- Известна ли эта проблема в iOS? Существуют ли соответствующие радары или официальная документация по этому поводу?
- Сталкивались ли другие разработчики с подобными проблемами, особенно когда CLHeading ведет себя некорректно, когда пользователь находится в движении?
- Нужно ли мне устанавливать какие-либо конкретные параметры в CLLocationManager (например, headingOrientation), чтобы решить или обойти эту проблему?
Подробнее здесь: https://stackoverflow.com/questions/798 ... tion-inste
Мобильная версия