简体   繁体   English

MKAnnotationView因EXEC_BAD_ACCESS而崩溃

[英]MKAnnotationView crashing with EXEC_BAD_ACCESS

I know EXC_BAD_ACCESS is one of those things hard to nail down, and I know about zombie mode to track down deallocated objects, but I'm still having trouble with this one. 我知道EXC_BAD_ACCESS是难以确定的事情之一,我知道僵尸模式可以追踪解除分配的对象,但我仍然遇到这个问题。

I have a custom MKAnnotation , and I'm using the standard AnnotationView on my map. 我有一个自定义的MKAnnotation ,我在我的地图上使用标准的AnnotationView。 When I tap on a pin on my map, I crash. 当我点击地图上的大头针时,我崩溃了。 If I zoom in so only 1 pin is shown, it works. 如果我放大所以只显示1个引脚,它就可以工作。 If I zoom back out and tap a new pin, it crashes. 如果我缩小并点击新的图钉,它会崩溃。 What's driving me crazy is that this was working (as far as i know) 100% yesterday and I don't remember changing any code (admittedly I had been up for 24 hours so... its possible I just don't remember doing it.) One time, I saw a pin give the title "com.apple.SOMETHING" before crashing. 让我抓狂的是,昨天(据我所知)这是100%有效的,而且我不记得更改任何代码(坦白地说,我已经工作了24小时,所以...我可能不记得这样做了)它。)有一次,我看到一个引脚在崩溃之前给出了标题“com.apple.SOMETHING”。 Sounds like an over release to me but the titles are stored in the annotations, I thought. 听起来像对我的过度释放,但标题存储在注释中,我想。

Zombie debugging gives: 僵尸调试提供:

*** -[CFString length]: message sent to deallocated instance 0x5b7b250. *** - [CFString length]:发送到解除分配的实例0x5b7b250的消息。

Nowhere in my map view or annotation class do I use string length. 我的地图视图或注释类中的任何地方都不会使用字符串长度。 I do have ONE photo with no title assigned, but it doesn't matter if that is the photo's pin that is tapped or visible on screen when the crash happens. 我确实有一张未分配标题的照片,但是当崩溃发生时,是否点击了照片的大头针或在屏幕上可见都没关系。

Here's the relevant code: 这是相关的代码:

MapAnnotation.h MapAnnotation.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import "Photo.h"

@interface MapAnnotation : NSObject <MKAnnotation> {
    CLLocationCoordinate2D coordinate;
    NSString *title;
    NSString *subtitle;
    Photo *photo;
}

-(id)initWithCoordinate:(CLLocationCoordinate2D)passCoordinate title:(NSString *)passTitle photo:(Photo *)passPhoto;

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *subtitle;
@property (nonatomic, retain) Photo *photo;

@end

MapAnnotation.m MapAnnotation.m

#import "MapAnnotation.h"

@implementation MapAnnotation

@synthesize title;
@synthesize subtitle;
@synthesize photo;
@synthesize coordinate;

-(id)initWithCoordinate:(CLLocationCoordinate2D)passCoordinate title:(NSString *)passTitle photo:(Photo *)passPhoto
{
    self = [super init];
    if (self) {
        // Custom initialization.
        coordinate = passCoordinate;
        title = passTitle;
        photo = passPhoto;
    }
    return self;
}

- (void)dealloc {
    [title release];
    [photo release];

    [super dealloc];
}

@end

MapViewController.h MapViewController.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "FlickrFetcher.h"
#import "Photo.h"
#import "Person.h"
#import "MapAnnotation.h"
#import "PhotoDetailViewController.h"


@interface MapViewController : UIViewController <MKMapViewDelegate> {
    IBOutlet MKMapView *mapView;
    FlickrFetcher *fetcher;
    NSArray *fetchedObjects;
    PhotoDetailViewController *photoDetail;
}

@property (retain, nonatomic) NSArray *fetchedObjects;

-(void)createAnnotations;

@end

And MapViewController.m 还有MapViewController.m

#import "MapViewController.h"

@implementation MapViewController

@synthesize fetchedObjects;

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    [self.navigationController setNavigationBarHidden:YES animated:NO];

    [mapView setDelegate:self];

    fetcher = [FlickrFetcher sharedInstance];

    // Setup a predicate that looks up all photos with non-zero latitide and longitude
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"longitude != 0 && latitude != 0"];

    fetchedObjects = [fetcher fetchManagedObjectsForEntity:@"Photo" withPredicate:predicate];

    [self createAnnotations];
}

- (void)viewWillAppear:(BOOL)animated
{
    [self.navigationController setNavigationBarHidden:YES animated:YES];
}

-(void)createAnnotations
{
    // iterate thorugh the array of photo objects, and setup annotation items, and put them on the map view
    for ( Photo *currentPhoto in fetchedObjects )
    {
        MapAnnotation *annotation;
        CLLocationCoordinate2D coordinate = {[[currentPhoto latitude] floatValue],[[currentPhoto longitude]floatValue]};
        annotation = [[MapAnnotation alloc] initWithCoordinate:coordinate title:[currentPhoto name] photo:currentPhoto];
        [mapView addAnnotation:annotation];
        [annotation release];
    }
}

#pragma mark -
#pragma mark Annotation View & Delegate Methods
- (MKAnnotationView *)mapView:(MKMapView *)thisMapView viewForAnnotation:(id <MKAnnotation>)annotation
{   
    MapAnnotation *myAnnotation = annotation;
    MKPinAnnotationView *annotationView;

    NSString* identifier = @"Pin";
    MKPinAnnotationView* pin = (MKPinAnnotationView*)[thisMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
    if(nil == pin) {
        pin = [[[MKPinAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
    }
    pin.animatesDrop = YES;
    annotationView = pin;
    UIButton *annotationButton=[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    annotationView.rightCalloutAccessoryView = annotationButton;
    [annotationView setEnabled:YES];
    [annotationView setCanShowCallout:YES];

    return annotationView;
}

- (void)mapView:(MKMapView *)thisMapView annotationView:(MKAnnotationView *)annotationView calloutAccessoryControlTapped:(UIControl *)control
{
    // Get the annoation from the annotation view that was tapped and make it into our custom protocol
    MapAnnotation *annotation = annotationView.annotation;
    Photo *photo = [annotation photo];
    photoDetail = [[PhotoDetailViewController alloc] initWithNibName:@"PhotoDetailViewController" bundle:[NSBundle mainBundle]];
    [photoDetail setPassedPhoto:photo];
    photoDetail.title = [NSString stringWithFormat:@"%@", [photo name]];
    [self.navigationController pushViewController:photoDetail animated:YES];
    [self.navigationController setNavigationBarHidden:NO animated:YES];

    [photoDetail release];
}

#pragma mark -
#pragma mark Memory Cleanup

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc. that aren't in use.
}

- (void)viewDidUnload {
    [super viewDidUnload];
}


- (void)dealloc {
    [mapView release];

    [super dealloc];
}

@end

And here's the backtrace: 这是回溯:

#0  0x01087057 in ___forwarding___ ()
#1  0x01086f22 in __forwarding_prep_0___ ()
#2  0x00eb9f81 in -[MKAnnotationContainerView _annotationViewForSelectionAtPoint:avoidCurrent:] ()
#3  0x00e89c99 in -[MKMapView handleTap:] ()
#4  0x005509c7 in -[UIGestureRecognizer _updateGestureWithEvent:] ()
#5  0x0054c9d6 in -[UIGestureRecognizer _delayedUpdateGesture] ()
#6  0x00552fa5 in _UIGestureRecognizerUpdateObserver ()
#7  0x010f6fbb in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#8  0x0108c0e7 in __CFRunLoopDoObservers ()
#9  0x01054bd7 in __CFRunLoopRun ()
#10 0x01054240 in CFRunLoopRunSpecific ()
#11 0x01054161 in CFRunLoopRunInMode ()
#12 0x01a4a268 in GSEventRunModal ()
#13 0x01a4a32d in GSEventRun ()
#14 0x002d642e in UIApplicationMain ()
#15 0x000023bc in main (argc=1, argv=0xbfffefd0) at /Users/chuck/Desktop/learning/flickr/main.m:14

When a crash occurs, there will be a backtrace. 发生崩溃时,会有回溯。

Post it. 发表它。

Either your program will break in the debugger, and the call stack will be in the debugger UI (or you can type 'bt 您的程序将在调试器中中断,并且调用堆栈将位于调试器UI中(或者您可以键入'bt

With that, the cause of the crash is often quite obvious. 因此,崩溃的原因通常非常明显。 Without that, we are left to critique the code. 如果没有这个,我们就会批评代码。

So, here goes.... 所以,这...


Zombie debugging gives: "* -[CFString length]: message sent to deallocated instance 0x5b7b250". 僵尸调试给出:“ *-[CFString length]:发送到已释放实例0x5b7b250的消息”。 Nowhere in my map view or annotation class do I use string length. 我的地图视图或注释类中的任何地方都不会使用字符串长度。

Yes, but you likely have strings that your code creates that are passed off to the system frameworks for rendering purposes or to be copied or whatever. 是的,但您可能拥有代码创建的字符串,这些字符串会传递给系统框架以用于呈现目的或被复制或其他任何内容。 And, likely, any one of those tasks requires the string's length. 而且,可能其中任何一项任务都需要字符串的长度。

When debugging zombies, it is helpful to look at the history of retains and releases on a particular object, which is available in the Allocations instrument. 在调试僵尸时,查看特定对象上的保留和释放的历史记录很有用,这在分配工具中可用。 Though on a slightly different subject, some of the screenshots and instructions in a post I wrote about find memory accretion may help. 虽然在一个稍微不同的主题上, 我写的关于查找内存增加的帖子中的一些屏幕截图和说明可能会有所帮助。

An obvious bug is that you don't retain the title passed in to your init method, but you release it in dealloc . 一个明显的错误是你没有保留传入init方法的title ,但你在dealloc释放它。 It should be retained; 应该保留它; self.title = passTitle; should do the trick. 应该做的伎俩。 Note that build and analyze should catch such bugs. 请注意, 构建和分析应捕获此类错误。 Same goes for the Photo parameter. Photo参数也是如此。

Note also that NSString properties should generally be copy and not retain . 另请注意, NSString属性通常应该是copy而不是retain Copying an immutable string is free and copying a mutable string greatly reduces potential fragility. 复制不可变字符串是免费的,复制可变字符串可以大大降低潜在的脆弱性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM