将 Parse PFGeoPoints 数组显示为地图注释错误
Display an array of Parse PFGeoPoints as Map Annotations Error
我试图在地图上显示存储在 NSArray 中的对象。在执行获取用户 2 英里范围内位置的方法后,对象从名为 Affiliates 的 Parse.com class 中提取。我已经使用 NSLog 来确认查询正在正确执行,所以我知道提取也正在正确执行。
当我尝试 运行 应用程序时,我在 for(NSDictionary) 部分抛出错误并且应用程序冻结。错误状态 "Thread 1: EXC_BAD_ACCESS (access code 1, address 0x80120)" 在咨询 Google 后,我发现这是某种类型的内存分配问题,但我不知道它为什么会发生或如何修复它。
#import "ViewController.h"
#import "MapAnnotation.h"
@import CoreLocation;
@interface ViewController () <CLLocationManagerDelegate>
@property (nonatomic,strong) NSArray *affiliates;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Ask for authorization to collect location from user
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
[locationManager requestWhenInUseAuthorization];
}
//Set map options
self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
self.mapView.scrollEnabled = YES;
self.mapView.zoomEnabled = YES;
self.mapView.userTrackingMode = YES;
// Store the user's location as a Parse PFGeoPoint and call the fetchAffiliatesNearPoint method
[PFGeoPoint geoPointForCurrentLocationInBackground:^(PFGeoPoint *geoPoint, NSError *error) {
if (!error) {
[self fetchAffiliatesNearPoint:geoPoint];
NSLog(@"Got User Location! %@", geoPoint);
}
}];
/* This is where I am having issues
for(NSDictionary *affiliates in affiliates) {
CLLocationCoordinate2D annotationCoordinate = CLLocationCoordinate2DMake([affiliates[@"latitude"] doubleValue], [affiliates[@"longitude"] doubleValue]);
MapAnnotation *annotation = [[MapAnnotation alloc] init];
annotation.coordinate = annotationCoordinate;
annotation.title = affiliates[@"name"];
annotation.subtitle = affiliates[@"url"];
[self.mapView addAnnotation:annotation];
}
*/
}
//Fetch an array of affiliates that are within two miles of the user's current location.
- (void)fetchAffiliatesNearPoint:(PFGeoPoint *)geoPoint
{
PFQuery *query = [PFQuery queryWithClassName:@"Affiliates"];
[query whereKey:@"geometry" nearGeoPoint:geoPoint withinMiles:2.0];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
self.affiliates = objects;
NSLog(@"Nearby Locations %@", _affiliates);
}
}];
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
//Zoom map to users current location
if (!self.initialLocation) {
self.initialLocation = userLocation.location;
MKCoordinateRegion mapRegion;
mapRegion.center = mapView.userLocation.coordinate;
mapRegion.span.latitudeDelta = .025;
mapRegion.span.longitudeDelta = .025;
[mapView setRegion:mapRegion animated: YES];
}
}
@end
如果要将自定义对象添加到 MapKit 地图,您的自定义对象必须符合 MKAnnotation
协议。只有一个 属性 您需要实现才能使您的对象符合协议:
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
其余属性(例如 title
和 subtitle
)和方法是可选的。
您需要做的就是在 PFGeoPoint 上创建一个类别(假设您正在使用 Objective-C)并为 coordinate
属性 实施 getter。
PFGeoPoint+Annotation.h
@interface PFGeoPoint (Annotation) <MKAnnotation>
@end
PFGeoPoint+Annotation.m
@implementation PFGeoPoint (Annotation)
- (CLLocationCoordinate2D)coordinate {
return CLLocationCoordinate2DMake(self.latitude, self.longitude);
}
@end
最后,要将其添加到地图,您将使用:
- (void)addAnnotation:(id <MKAnnotation>)annotation;
例如:[mapView addAnnotation:geoPoint];
我也没有使用过 Parse,但有几个明显的问题可能会有所帮助:
这行没有意义:
for(NSDictionary *affiliates in affiliates)
这里,in
之后的affiliates
指的是locally声明的字典变量,not指的是属性 同名变量。由于局部变量没有初始化引用并且指向一些随机内存,所以你得到 EXC_BAD_ACCESS
。使用 self.affiliates
明确引用 属性.
此外,非常 将循环变量命名为与它正在循环的数组相同的名称会令人困惑。您正在遍历 "affiliates"(复数)数组。该数组包含字典,每个字典都是 "affiliate"(单数)。将字典变量命名为 affiliate
(单数)会更容易混淆。示例:
for (NSDictionary *affiliate in self.affiliates)
同时将循环内剩余的引用从 affiliates
更改为 affiliate
。
目前,self.affiliates
上的循环是在 geoPointForCurrentLocationInBackground
开始 后立即完成的。 geoPointForCurrentLocationInBackground
似乎是异步的,这意味着 self.affiliates
上的循环将在 geoPointForCurrentLocationInBackground
实际设置 属性 之前执行 。
不要在 geoPointForCurrentLocationInBackground
开始后立即在 viewDidLoad
中循环 self.affiliates
,而是将循环移动到 findObjectsInBackgroundWithBlock
的完成块内(之后 self.affiliates
已设置)。示例:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
self.affiliates = objects;
NSLog(@"Nearby Locations %@", _affiliates);
for(NSDictionary *affiliate in self.affiliates) {
...
}
}
}];
我试图在地图上显示存储在 NSArray 中的对象。在执行获取用户 2 英里范围内位置的方法后,对象从名为 Affiliates 的 Parse.com class 中提取。我已经使用 NSLog 来确认查询正在正确执行,所以我知道提取也正在正确执行。
当我尝试 运行 应用程序时,我在 for(NSDictionary) 部分抛出错误并且应用程序冻结。错误状态 "Thread 1: EXC_BAD_ACCESS (access code 1, address 0x80120)" 在咨询 Google 后,我发现这是某种类型的内存分配问题,但我不知道它为什么会发生或如何修复它。
#import "ViewController.h"
#import "MapAnnotation.h"
@import CoreLocation;
@interface ViewController () <CLLocationManagerDelegate>
@property (nonatomic,strong) NSArray *affiliates;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Ask for authorization to collect location from user
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
[locationManager requestWhenInUseAuthorization];
}
//Set map options
self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
self.mapView.scrollEnabled = YES;
self.mapView.zoomEnabled = YES;
self.mapView.userTrackingMode = YES;
// Store the user's location as a Parse PFGeoPoint and call the fetchAffiliatesNearPoint method
[PFGeoPoint geoPointForCurrentLocationInBackground:^(PFGeoPoint *geoPoint, NSError *error) {
if (!error) {
[self fetchAffiliatesNearPoint:geoPoint];
NSLog(@"Got User Location! %@", geoPoint);
}
}];
/* This is where I am having issues
for(NSDictionary *affiliates in affiliates) {
CLLocationCoordinate2D annotationCoordinate = CLLocationCoordinate2DMake([affiliates[@"latitude"] doubleValue], [affiliates[@"longitude"] doubleValue]);
MapAnnotation *annotation = [[MapAnnotation alloc] init];
annotation.coordinate = annotationCoordinate;
annotation.title = affiliates[@"name"];
annotation.subtitle = affiliates[@"url"];
[self.mapView addAnnotation:annotation];
}
*/
}
//Fetch an array of affiliates that are within two miles of the user's current location.
- (void)fetchAffiliatesNearPoint:(PFGeoPoint *)geoPoint
{
PFQuery *query = [PFQuery queryWithClassName:@"Affiliates"];
[query whereKey:@"geometry" nearGeoPoint:geoPoint withinMiles:2.0];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
self.affiliates = objects;
NSLog(@"Nearby Locations %@", _affiliates);
}
}];
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
//Zoom map to users current location
if (!self.initialLocation) {
self.initialLocation = userLocation.location;
MKCoordinateRegion mapRegion;
mapRegion.center = mapView.userLocation.coordinate;
mapRegion.span.latitudeDelta = .025;
mapRegion.span.longitudeDelta = .025;
[mapView setRegion:mapRegion animated: YES];
}
}
@end
如果要将自定义对象添加到 MapKit 地图,您的自定义对象必须符合 MKAnnotation
协议。只有一个 属性 您需要实现才能使您的对象符合协议:
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
其余属性(例如 title
和 subtitle
)和方法是可选的。
您需要做的就是在 PFGeoPoint 上创建一个类别(假设您正在使用 Objective-C)并为 coordinate
属性 实施 getter。
PFGeoPoint+Annotation.h
@interface PFGeoPoint (Annotation) <MKAnnotation>
@end
PFGeoPoint+Annotation.m
@implementation PFGeoPoint (Annotation)
- (CLLocationCoordinate2D)coordinate {
return CLLocationCoordinate2DMake(self.latitude, self.longitude);
}
@end
最后,要将其添加到地图,您将使用:
- (void)addAnnotation:(id <MKAnnotation>)annotation;
例如:[mapView addAnnotation:geoPoint];
我也没有使用过 Parse,但有几个明显的问题可能会有所帮助:
这行没有意义:
for(NSDictionary *affiliates in affiliates)
这里,
in
之后的affiliates
指的是locally声明的字典变量,not指的是属性 同名变量。由于局部变量没有初始化引用并且指向一些随机内存,所以你得到EXC_BAD_ACCESS
。使用self.affiliates
明确引用 属性.此外,非常 将循环变量命名为与它正在循环的数组相同的名称会令人困惑。您正在遍历 "affiliates"(复数)数组。该数组包含字典,每个字典都是 "affiliate"(单数)。将字典变量命名为
affiliate
(单数)会更容易混淆。示例:for (NSDictionary *affiliate in self.affiliates)
同时将循环内剩余的引用从
affiliates
更改为affiliate
。目前,
self.affiliates
上的循环是在geoPointForCurrentLocationInBackground
开始 后立即完成的。geoPointForCurrentLocationInBackground
似乎是异步的,这意味着self.affiliates
上的循环将在geoPointForCurrentLocationInBackground
实际设置 属性 之前执行 。不要在
geoPointForCurrentLocationInBackground
开始后立即在viewDidLoad
中循环self.affiliates
,而是将循环移动到findObjectsInBackgroundWithBlock
的完成块内(之后self.affiliates
已设置)。示例:[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { if (!error) { self.affiliates = objects; NSLog(@"Nearby Locations %@", _affiliates); for(NSDictionary *affiliate in self.affiliates) { ... } } }];