我有一个使用 GoogleMap View 的应用。
在该应用程序中,我想显示一些自定义注释和 userLocation 的自定义 View 。当位置管理器给出一个标题时,我想显示 userLocation 的自定义 View ,如果它无法提供一个,我希望默认的蓝色动画点回来,等等......
项目和源代码可用 HERE
嗯,这里有两个问题:
第一个问题,非常糟糕。您可以使用这个小应用程序玩几个小时。但是......启动它,等待它加载,将它发送到后台,将你的 iPhone 置于 sleep 模式,等一下,唤醒你的 iPhone,启动应用程序(唤醒它):崩溃,EXC_BAD_ACCESS。做同样的事情,不要让 iPhone 进入休眠模式:不会崩溃。不是等待一分钟而是几秒钟,没有崩溃。 10 秒,没有崩溃,20 秒,没有崩溃,将近 30 秒,可能会崩溃,将近一分钟,崩溃!
第二个问题(奖励 :-)), 可以与第一个问题联系起来,但这并不是这个问题的真正核心:我用来实现 userPinLocation 更新的解决方案/to the blue pin 似乎有一个非常糟糕的副作用:当你在街上移动时,userLocation 不会在 map 上移动。对于第二个问题的任何答案,如果它与崩溃没有直接关系,请使用评论而不是答案。这不是问题的核心……我认为……
为了找到错误代码,我已将我的应用程序缩减到最低限度。这给出了以下代码(源代码中的一些提示作为注释):
EXC_BAD_ACCESS_TestViewController.h
#import <MapKit/MapKit.h>
@interface EXC_BAD_ACCESS_TestViewController : UIViewController<CLLocationManagerDelegate> {
CLLocationManager* locationMgr;
NSMutableArray* customAnnotations;
CLLocationDirection userHeading;
MKMapView* myMapView;
}
@property(nonatomic, retain) CLLocationManager* locationMgr;
@property(nonatomic, retain) NSMutableArray* customAnnotations;
@property(nonatomic, assign) CLLocationDirection userHeading;
@property(nonatomic, retain) IBOutlet MKMapView* myMapView;
- (void) loadAnnotations;
@end
EXC_BAD_ACCESS_TestViewController.m
// On first launch, due to code simplification, the app may crash when asked authorization to use geo hardware. Just kill/relaunch after accepting.
// Breakpoints on each method entry : EXC_BAD_ACCESS crash without any break-stop
#import "EXC_BAD_ACCESS_TestViewController.h"
#import "CustomAnnotation.h"
@implementation EXC_BAD_ACCESS_TestViewController
@synthesize locationMgr, customAnnotations, myMapView, userHeading;
// ===========================================================================================================
-(id) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self) return nil;
self.userHeading = -1;
return self;
}
// ===========================================================================================================
- (void) viewDidLoad
{
[self loadAnnotations];
self.myMapView.mapType = MKMapTypeStandard;
self.myMapView.showsUserLocation = YES;
// -----------------------------------------------
// Just comment this sole line : no more crash
// -----------------------------------------------
for (CustomAnnotation* pin in self.customAnnotations) [self.myMapView addAnnotation:pin];
// locationManager
self.locationMgr = [[CLLocationManager alloc] init];
self.locationMgr.desiredAccuracy = kCLLocationAccuracyBest;
self.locationMgr.distanceFilter = 1.0;
self.locationMgr.headingFilter = 1.0;
self.locationMgr.purpose = @"Some purpose.";
self.locationMgr.delegate = self;
[self.locationMgr startUpdatingHeading];
[super viewDidLoad];
}
// ===========================================================================================================
- (void) loadAnnotations
{
// Code for testing, real code gets the datas using another way of doing, as simple as this one
self.customAnnotations = [NSMutableArray array];
double latitude = 45.0;
double longitude = -45.0;
for (int i=1; i<=400; i++) {
CLLocationCoordinate2D pinLocation = CLLocationCoordinate2DMake(latitude, longitude);
CustomAnnotation* pin = [[[CustomAnnotation alloc] initWithCoordinate:pinLocation] autorelease];
[self.customAnnotations addObject:pin];
latitude += 0.01;
longitude += 0.01;
}
}
// ===========================================================================================================
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
MKAnnotationView* pinView = nil;
NSString* annotationIdentifier;
UIImage* pinImage;
BOOL canShowCallout;
// User location
if ([annotation isKindOfClass:[MKUserLocation class]] && self.userHeading >= 0) {
annotationIdentifier = @"UserLocationAnnotation";
pinImage = [UIImage imageNamed:@"custom_userlocation.png"];
canShowCallout = NO;
}
// Custom Pin
else if ([annotation isKindOfClass:[CustomAnnotation class]]) {
annotationIdentifier = @"CustomAnnotation";
pinImage = [UIImage imageNamed:@"custom_pin.png"];
canShowCallout = YES;
}
// Others
else {
return nil;
}
pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (pinView) {
pinView.annotation = annotation;
}
else {
pinView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier] autorelease];
if (pinView) {
pinView.image = pinImage;
pinView.canShowCallout = canShowCallout;
if (canShowCallout) {
pinView.calloutOffset = CGPointMake(-5, 5);
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
}
}
return pinView;
}
// -----------------------------------------------
// Just comment this method : no more crash
// -----------------------------------------------
// ===========================================================================================================
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
if (!self.myMapView) return;
if (!self.myMapView.userLocation) return;
CLLocationDirection compassHeading_True = newHeading.trueHeading;
CLLocationDirection compassHeading_Magnetic = newHeading.magneticHeading;
CLLocationDirection heading;
if (compassHeading_True == -1) heading = compassHeading_Magnetic;
else if (newHeading.headingAccuracy >= 0) heading = compassHeading_True;
else heading = -1;
// If we get/loose the heading, update pin image
// I didn't found any other solution to force the user pin to update its display.
if ((self.userHeading == -1 || heading == -1) && self.userHeading != heading) {
[self.myMapView removeAnnotation:self.myMapView.userLocation];
self.userHeading = heading;
[self.myMapView addAnnotation:self.myMapView.userLocation];
}
self.userHeading = heading;
// ------------------------------------
// Some non bugued code was there
// ------------------------------------
}
// ===========================================================================================================
- (void) dealloc
{
self.myMapView = nil;
self.customAnnotations = nil;
self.locationMgr = nil;
[super dealloc];
}
@end
自定义注释.h
#import <MapKit/MapKit.h>
@interface CustomAnnotation : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
}
@property(nonatomic, assign) CLLocationCoordinate2D coordinate;
- (id)initWithCoordinate:(CLLocationCoordinate2D) c;
@end
自定义注释.m
#import "CustomAnnotation.h"
@implementation CustomAnnotation
@synthesize coordinate;
// ===========================================================================================================
- (id)initWithCoordinate:(CLLocationCoordinate2D) c
{
self = [super init];
if (!self) return nil;
self.coordinate = c;
return self;
}
// ===========================================================================================================
- (NSString*)subtitle
{
return @"";
}
// ===========================================================================================================
- (NSString*)title
{
return @"";
}
@end
我在每种方法中都尝试了断点,尝试使用环境变量启用 Zombies(但由于这需要在设备上运行,我不确定它们是否真的被激活),没有任何解决方案的开始......我仍然不知道出了什么问题。
您知道如何解决 EXC_BAD_ACCESS 问题吗?
对于第二个问题的任何答案,如果不能解决崩溃,请使用评论而不是答案。据我所知,这个问题不是问题的核心。
提示:我在上面的代码中添加了 2 条注释,在那里我找到了一些解决方案。有 2 个地方似乎没有连接,可以从代码中取出一个或另一个来解决问题。让我抓狂的是手术室。
在 iPhone 4 ios 4.2.1 上运行
最佳答案
[self.myMapView removeAnnotation:self.myMapView.userLocation];
这条线导致堆栈跟踪崩溃,这是我所看到的。
当我看到 exc_bad_access 时,我在 gdb 中做了一个 bt。我添加了 Guard Malloc 断点。查看它所说的关于删除注释的堆栈。
关于ios - iPhone - 需要一些关于 EXC_BAD_ACCESS 的帮助,这让我发疯(包括完整的源代码),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7409404/