扩展 CLPlacemark 导致 EXC BAD ACCESS
Extending CLPlacemark results in EXC BAD ACCESS
虽然找到了类似的问题here但它没有提供答案,至少不是针对一般问题。
我的问题是:
由于 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
的重新分配出现了问题 - 但究竟是什么?
非常感谢任何帮助!
作为任何登陆这里遇到类似问题的人的参考:
经过深入 Google-Fu 和深入研究 Apple 的源代码后,似乎并不打算扩展 CLPlacemark
。
但是,我能够根据找到的提示 here 实施变通方法,这基本上滥用了 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!
我的 swift 模拟 class:
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()
}
}
希望它能为其他人节省一些时间。干杯!
虽然找到了类似的问题here但它没有提供答案,至少不是针对一般问题。
我的问题是:
由于 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
的重新分配出现了问题 - 但究竟是什么?
非常感谢任何帮助!
作为任何登陆这里遇到类似问题的人的参考:
经过深入 Google-Fu 和深入研究 Apple 的源代码后,似乎并不打算扩展 CLPlacemark
。
但是,我能够根据找到的提示 here 实施变通方法,这基本上滥用了 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!
我的 swift 模拟 class:
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()
}
}
希望它能为其他人节省一些时间。干杯!