iPhone - 需要一些关于 EXC_BAD_ACCESS 的帮助,这让我发疯(包括完整的源代码)

发布于 2024-12-04 05:20:29 字数 8397 浏览 3 评论 0原文

我有一个使用 GoogleMap 视图的应用程序。
在该应用程序中,我想显示一些自定义注释以及 userLocation 的自定义视图。当位置管理器给出标题时,我想显示 userLocation 的自定义视图,如果它无法提供一个,我希望默认的蓝色动画点返回,等等...

可用的项目和源代码这里

嗯,这里有两个问题:

第一个问题,真正的问题坏的一。您可以使用这个小应用程序玩几个小时。但是...启动它,等待它加载,将其发送到后台,将您的 iPhone 置于睡眠模式,稍等一下,唤醒您的 iPhone,启动应用程序(唤醒它):崩溃,EXC_BAD_ACCESS。执行同样的操作,但不要将 iPhone 置于睡眠模式:不会崩溃。不是等一分钟而是等几秒钟,没有崩溃。 10秒,没有崩溃,20秒,没有崩溃,接近30秒,也许崩溃,接近一分钟,崩溃!

第二个问题(奖励:-)),可以与第一个问题联系起来,但这并不是这个问题的核心:我用来实现 userPinLocation 更新的解决方案蓝色图钉似乎有一个非常糟糕的副作用:当您在街道上移动时,用户位置不会在地图上移动。对于第二个问题的任何答案,如果它与崩溃没有直接联系,请使用评论而不是答案。这不是问题的核心......我认为......

为了找到错误代码,我已经将我的应用程序减少到了最低限度。这给出了以下代码(源代码中的一些提示作为注释):

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

CustomAnnotation.h

#import <MapKit/MapKit.h>

@interface CustomAnnotation : NSObject<MKAnnotation> {
    CLLocationCoordinate2D coordinate;
}

@property(nonatomic, assign) CLLocationCoordinate2D coordinate;

- (id)initWithCoordinate:(CLLocationCoordinate2D) c;
@end

CustomAnnotation.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

我在每个方法中尝试了断点,尝试使用环境变量启用僵尸(但因为这需要运行在设备上,我不确定它们是否真的被激活),没有任何解决方案的开始......我仍然不知道出了什么问题。

您知道如何解决 EXC_BAD_ACCESS 问题吗?
对于第二个问题的任何答案,如果不能解决崩溃问题,请使用评论而不是答案。据我所知,这个问题并不是问题的核心。

提示:我在上面的代码中添加了 2 条注释,我在其中找到了一些解决方案的开始。有 2 个地方似乎没有连接,可以将其中一个或另一个从代码中取出来解决问题。让我疯狂的是 OR。

在 iPhone 4 ios 4.2.1 上运行

I have an app that uses a GoogleMap view.
Into that app, I want to display some custom anotations, and a custom view for the userLocation. When the location manager gives a heading, I want to display that custom view for userLocation, if it fails to deliver one, I want the default blue animated dot to come back, etc...

Project and Source code available HERE

Well, there are 2 problems here :

1st problem, THE REALLY BAD ONE. You can play for hours with that tiny app. But... Launch it, wait it loads, send it to the background, put your iPhone in sleep mode, wait a minute, wake up your iPhone, launch the app (that wakes it up) : crash, EXC_BAD_ACCESS. Do the same thing not putting the iPhone in sleep mode : no crash. Not waiting for a minute but a few seconds, no crash. 10 seconds, no crash, 20 seconds, no crash, nears 30 seconds, perhaps a crash, near a minute, crash !

2nd problem (bonus :-) ), that can be linked with the first one, but that is not really the heart of this question : the solution I use to achieve the userPinLocation to update from/to the blue pin seems to have a really bad side effect : the userLocation does not move on the map as you move in the street. For any answer for that 2nd problem, if it's not directly linked with the crash, please use comments not answers. This is not the heart of the question... I think...

To find the faulty code, I've reduced my app at its minimum. That gives the following code (some tips in the source code as comments) :

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

CustomAnnotation.h

#import <MapKit/MapKit.h>

@interface CustomAnnotation : NSObject<MKAnnotation> {
    CLLocationCoordinate2D coordinate;
}

@property(nonatomic, assign) CLLocationCoordinate2D coordinate;

- (id)initWithCoordinate:(CLLocationCoordinate2D) c;
@end

CustomAnnotation.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

I tried breakpoints in each methods, trying to enable Zombies with environment variables (but as this needs to be ran on the device, I'm not sure they've been really activated), without any start of solution... I still don't have any idea of what's going wrong.

Do you see how to solve that EXC_BAD_ACCESS problem ?
For any answer for the 2nd problem, please use comments and not answers if it don't solve the crash. This problem is not the heart of the question as far as I've seen.

Tip : I've put 2 comments in the code above where I found some start of solution. There are 2 places, that does not seems connected, that can be put out of the code one OR the other to solve the problem. What makes me crazy is the OR.

Runned on an iPhone 4 ios 4.2.1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡写薰衣草的香 2024-12-11 05:20:29
[self.myMapView removeAnnotation:self.myMapView.userLocation];

这条线导致堆栈跟踪崩溃,这是我所看到的。

当我看到 exc_bad_access 时,我在 gdb 中做了一个 bt。我添加了 Guard Malloc 断点。查看堆栈,它说关于删除注释。

[self.myMapView removeAnnotation:self.myMapView.userLocation];

This line is causing the crash from stacktrace this is what I've seen.

When I saw exc_bad_access I did a bt in gdb. I have added Guard Malloc breakpoint. Looking at the stack it said about removing annotation.

一世旳自豪 2024-12-11 05:20:29

您可以尝试重写视图控制器 .m 文件中名为 didReceiveMemoryWarning 的方法。

有时会发生这样的情况:由于正在运行的应用程序,设备上的内存会变低,并且 IOS 会向应用程序发送一条消息。现在的问题是,当您不重写内存警告方法时,它的默认操作是从内存中删除任何不可见的子视图。当您的应用程序运行时,这可能会导致僵尸变量。

查看 Apple 文档

You can try overriding a method called didReceiveMemoryWarning in your view controller .m file.

What happens sometimes is that memory on the device gets low due to running apps and IOS sends a message to the app. Now the trouble is when you don't override memory warning method, its default action is to remove any subviews from memory which are not visible. This can lead to zombie variables when your application runs.

Check out the apple doc

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文