Расширение CLPlacemark приводит к EXC BAD ACCESS

Хотя здесь есть похожий вопрос, он не дает ответа, по крайней мере, не для общей проблемы.

Моя проблема: с CoreLocation геокодирование ограничено по скорости, и (веб-) служба, для которой я разрабатываю приложение, предоставляет собственную резервную службу геокодирования, я хочу использовать эту специальную службу геокодирования на случай, если я достигну предела скорости Apple. Кроме того, я считаю, что имеет смысл избегать использования пользовательского типа данных для результатов, возвращаемых этим пользовательским REST API, и поэтому хотел бы использовать данные, возвращаемые для создания CLPlacemark s. Однако в документации говорится, что CLPlacemark свойства, такие как location, locality, administrativeArea и т. д. read-only, Поэтому я создал подкласс CLPlacemark синтезировать необходимые свойства на частные переменные, к которым я могу получить доступ, то есть:

// interface: (.h)
@interface CustomPlacemark : CLPlacemark
- (nonnull id)initWithLocation: (nonnull CLLocation *)location
                      locality: (nullable NSString *)locality                       
            administrativeArea: (nullable NSString *)adminArea
                       country: (nullable NSString *)country;
@end

// implementation (.m)
@implementation CustomPlacemark
@synthesize location = _location;
@synthesize locality = _locality;
@synthesize country = _country;
@synthesize administrativeArea = _administrativeArea;

- (nonnull id)initWithLocation: (nonnull CLLocation *)location
                          locality: (nullable NSString *)locality
                administrativeArea: (nullable NSString *)adminArea
                           country: (nullable NSString *)country{
    self = [super init];
    if(self){
        _location = location;
        _locality = locality;
        _administrativeArea = adminArea;
        _country = country;
    }
    return self;
}
@end

Тестирование этого кода с помощью модульного теста, который анализирует данные из файла JSON и вызывает мой initWithLocation: locality: administrativeArea: country: Метод с данными приводит к EXC BAD ACCESS (code=1) в конце теста (при закрытии } метода тестирования) с переменной метки, указывающей на nil хотя до NSLog(@"placemark: %@", customPlacemark); выводит правильные значения. Кроме того, шаг за шагом тестирование показывает CustomPlacemark работать (т.е. указывать на правильно заполненный объект) до достижения конца теста. Для меня это указывает на то, что что-то с освобождением моего CustomPlacemark идет не так - но что именно?

Любая помощь очень ценится!

1 ответ

Решение

Как ссылка на любого приземляющегося здесь с похожей проблемой:

После некоторого интенсивного Google-Fu и глубокого погружения в источники Apple, кажется, что расширение CLPlacemark не предназначен.

Я, однако, смог реализовать обходной путь на основе советов, найденных здесь, который в основном злоупотребляет тем фактом, что MKPlacemark продолжается CLPlacemark и предлагает метод для инициализации с пользовательскими данными, а именно - (instancetype _Nonnull)initWithCoordinate:(CLLocationCoordinate2D)coordinate addressDictionary:(NSDictionary<NSString *, id> * _Nullable)addressDictionary, Нахождение правильных ключей для addressDictionary для сопоставления желаемых свойств в CLPlacemark может потребовать проб и ошибок, тем более что ABPerson/Addressфункциональность стала устаревшей с iOS 9. Ключи, которые я нашел для моих целей:

@"City" -> CLPlacemark.city
@"State" -> CLPlacemark.administrativeArea
@"Country" -> CLPlacemark.country

Спасибо @hpd!

Мой быстрый макет класса:

class TestPlacemark: CLPlacemark {
    static let coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(35), longitude: CLLocationDegrees(-80))

    override init() {
        let mkPlacemark = MKPlacemark(coordinate: TestPlacemark.coordinate) as CLPlacemark
        super.init(placemark: mkPlacemark)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override static var supportsSecureCoding: Bool {
        return false
    }
    override var location: CLLocation? {
        return CLLocation(latitude: TestPlacemark.coordinate.latitude, longitude: TestPlacemark.coordinate.longitude)
    }
    override var postalAddress: CNPostalAddress?  {
        return TestPostalAddress()
    }
}

Надеюсь, это сэкономит время кому-то еще. Ура!

Другие вопросы по тегам