如何在iPhone上避免MKMapKit相关崩溃

时间:2009-11-07 22:10:12

标签: iphone annotations mkmapview

因此,在过去的几天里,我一直在努力了解如何使用一些自定义注释实现简单的 MKMapView ,而不会在此过程中崩溃我的应用程序。不幸的是,我无法确定我做错了什么,并且在这个过程中变得越来越沮丧。

我想要完成的事情应该相对简单。我正在尝试创建一个与其关联的位置的新对象。为此,我有一个用于创建对象的视图控制器。我希望用户能够在任何时候取消视图控制器,但是为了保存对象,他们必须首先为它提供位置和名称。该名称将通过 UITextField 获取,而位置将通过MKMapView获取。

所以这就是发生的事情......每当我打开新对象视图控制器时,它都会更新位置和诸如此类的东西。如果我尝试单击取消,它会崩溃。为了简化问题,我删除了更新位置和移动注释引脚的代码,因此您不会在下面看到。

除了我在崩溃后遇到的堆栈跟踪示例之外,还有一些我正在使用的代码。我们将非常感谢您提供的任何帮助。谢谢!

在我向您展示我的代码之前,这里是我最终得到的堆栈跟踪:

崩溃后的堆栈跟踪

#1 0x30c4c8b8 in -[UIImageView stopAnimating]
#2 0x30c4c810 in -[UIImageView dealloc]
#3 0x32d86640 in -[NSObject release]
#4 0x32d198ac in -[MKAnnotationView dealloc]
#5 0x32d86640 in -[NSObject release]
#6 0x30bfab34 in -[UIView(Hierarchy) removeFromSuperview]
#7 0x30c4ca24 in -[UIView dealloc]
#8 0x32ce881c in -[MKOverlayView dealloc]
#9 0x32d86640 in -[NSObject release]
#10 0x30bfab34 in -[UIView(Hierarchy) removeFromSuperview]
#11 0x30c4ca24 in -[UIView dealloc]
#12 0x30cbb878 in -[UIScrollView dealloc]
#13 0x32d179c4 in -[MKScrollView dealloc]
#14 0x32d86640 in -[NSObject release]
#15 0x30bfab34 in -[UIView(Hierarchy) removeFromSuperview]
#16 0x30cbb4a8 in -[UIScrollView removeFromSuperview]
#17 0x30c4ca24 in -[UIView dealloc]
#18 0x32d86640 in -[NSObject release]
#19 0x30bfab34 in -[UIView(Hierarchy) removeFromSuperview]
#20 0x30c4ca24 in -[UIView dealloc]
#21 0x32cc579c in -[MKMapView dealloc]
#22 0x32d86640 in -[NSObject release]
#23 0x30bfab34 in -[UIView(Hierarchy) removeFromSuperview]
#24 0x30c4ca24 in -[UIView dealloc]
#25 0x32d86640 in -[NSObject release]
#26 0x30bfab34 in -[UIView(Hierarchy) removeFromSuperview]
#27 0x30c4ca24 in -[UIView dealloc]
#28 0x32d86640 in -[NSObject release]
#29 0x30bfab34 in -[UIView(Hierarchy) removeFromSuperview]
#30 0x30c4ca24 in -[UIView dealloc]
#31 0x32d86640 in -[NSObject release]
#32 0x30bfab34 in -[UIView(Hierarchy) removeFromSuperview]
#33 0x30c4ca24 in -[UIView dealloc]
#34 0x32d86640 in -[NSObject release]
#35 0x33f70996 in NSPopAutoreleasePool
#36 0x33e99104 in run_animation_callbacks
#37 0x33e98e6c in CA::timer_callback
#38 0x32da44c2 in CFRunLoopRunSpecific
#39 0x32da3c1e in CFRunLoopRunInMode
#40 0x31bb9374 in GSEventRunModal
#41 0x30bf3c30 in -[UIApplication _run]
#42 0x30bf2230 in UIApplicationMain
#43 0x00002450 in main at main.m:14

CustomAnnotation.h

@interface CustomAnnotation : NSObject <MKAnnotation, 
          MKReverseGeocoderDelegate>
{
 @private
 MKReverseGeocoder*   _reverseGeocoder;
 MKPlacemark*    _placemark;

 @public
 CLLocationCoordinate2D  _coordinate;
 NSString*     _title;
}

//Note: Property for CLLocationCoordinate2D coordinate is declared in MKAnnotation
@property (nonatomic, retain) NSString*      title;
@property (nonatomic, retain) MKPlacemark*   placemark;

-(id) initWithCoordinate:(CLLocationCoordinate2D)coordinate
       title:(NSString*)title;

-(void) setCoordinate:(CLLocationCoordinate2D)coordinate;

@end

CustomAnnotation.m

@implementation CustomAnnotation

@synthesize coordinate      = _coordinate; // property declared in MKAnnotation.h
@synthesize title   = _title;
@synthesize placemark  = _placemark;

-(id) initWithCoordinate:(CLLocationCoordinate2D)coordinate 
       title:(NSString*)title
{
 if(self = [super init])
 {
  _title      = [title retain];
  [self setCoordinate:coordinate];
  _placemark = nil;
 }
 return self;
}

#pragma mark -
#pragma mark MKAnnotationView Notification

- (void)notifyCalloutInfo:(MKPlacemark *)newPlacemark {
 [self willChangeValueForKey:@"subtitle"]; // Workaround for SDK 3.0, otherwise callout info won't update.
 self.placemark = newPlacemark;
 [self didChangeValueForKey:@"subtitle"]; // Workaround for SDK 3.0, otherwise callout info won't update.

 [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"MKAnnotationCalloutInfoDidChangeNotification" object:self]];
}

#pragma mark
#pragma mark -
#pragma mark Reverse Geocoder Reset Procedure

- (void)resetReverseGeocoder
{
 if(_reverseGeocoder != nil)
 {
  //If the reverse geocoder already exists, check to make sure it isn't querying. Cancel query if it is.
  if([_reverseGeocoder isQuerying])
  {
   [_reverseGeocoder cancel];
  }

  //Before releasing the reverse geocoder, set it's delegate to nil just to be safe
  [_reverseGeocoder setDelegate:nil];

  //Release the current reverse geocoder
  [_reverseGeocoder release];
  _reverseGeocoder = nil;
 }
}

#pragma mark
#pragma mark -
#pragma mark Set Coordinate Procedure

- (void)setCoordinate:(CLLocationCoordinate2D)coordinate {
 _coordinate = coordinate;

 //We only want to be reverse geocoding one location at a time, so make sure we've reset the reverse geocoder before starting
 [self resetReverseGeocoder];

 //Create a new reverse geocoder to find the location for the given coordinate, and start the query
 _reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:_coordinate];
 [_reverseGeocoder setDelegate:self];
 [_reverseGeocoder start];
}

#pragma mark
#pragma mark -
#pragma mark MKAnnotation Delegate Procedure Implementations

- (NSString *)subtitle
{
 NSString* subtitle = nil;

if (_placemark) 
 {
   subtitle = [NSString stringWithString:[[_placemark.addressDictionary objectForKey:@"FormattedAddressLines"] objectAtIndex:1]];
  } 
  else 
  {
   subtitle = [NSString stringWithFormat:@"%lf, %lf", _coordinate.latitude, _coordinate.longitude];
  }

 return subtitle;
}

#pragma mark -
#pragma mark MKReverseGeocoderDelegate methods

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)newPlacemark {

 if(geocoder != _reverseGeocoder)
 {
  NSLog(@"WARNING:::: MORE THAN ONE REVERSE GEOCODER!!!");
  NSLog(@"_reverseGeocoder = %@",[_reverseGeocoder description]);
  NSLog(@"geocoder = %@",[geocoder description]);
 }

 [self notifyCalloutInfo:newPlacemark];

 [self resetReverseGeocoder];
}

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {

 if(geocoder != _reverseGeocoder)
 {
  NSLog(@"WARNING:::: MORE THAN ONE REVERSE GEOCODER!!!");
  NSLog(@"_reverseGeocoder = %@",[_reverseGeocoder description]);
  NSLog(@"geocoder = %@",[geocoder description]);
 }

 [self notifyCalloutInfo:nil];

 [self resetReverseGeocoder];
}


#pragma mark -
#pragma mark Memory Management

- (void)dealloc {

 [self resetReverseGeocoder];

 [_title   release], _title = nil;
 [_placemark  release], _placemark = nil;

 [super dealloc];
}

@end

其次,我创建了一个自定义注释视图

CustomAnnotationView.h

@interface CustomAnnotationView : MKAnnotationView {

}

@end

CustomAnnotationView.m

@implementation CustomAnnotationView

- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
 self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];

 UIGraphicsBeginImageContext(CGSizeMake(30,30));

        //Note: [UIImage drawInRect:radius:contentMode:] is a Three20 Procedure
 [[UIImage imageNamed:@"annoationIcon.png"] drawInRect:CGRectMake(0,0,30,30) radius:6.0f contentMode:UIViewContentModeScaleAspectFill];

 UIImage *iconImage = UIGraphicsGetImageFromCurrentImageContext();

 //pop the context to get back to the default
 UIGraphicsEndImageContext();

 UIImageView *leftIconView = [[UIImageView alloc] initWithImage:iconImage];
 self.leftCalloutAccessoryView = leftIconView;
 [leftIconView release];

 [iconImage release];

 return self;
}

@end

而且,最后但并非最不重要的是,我的新对象视图控制器的相关部分:

NewObjectViewController.m

@implementation NewObjectViewController

@synthesize managedObjectContext;

@synthesize object;

@synthesize objectMapView;

#pragma mark
#pragma mark -
#pragma mark Initialization

-(id) initWithManagedObjectContext:(NSManagedObjectContext*)context{
 self = [super init];
 if (self != nil) {

  [self setManagedObjectContext:context]; 

  Object *newObject = [NSEntityDescription insertNewObjectForEntityForName:@"Object" inManagedObjectContext:self.managedObjectContext];
  self.object = [newObject retain];

 }
 return self;
}


#pragma mark
#pragma mark -
#pragma mark Memory Management

-(void) dealloc {

    [object release], object=nil

 objectMapView.delegate = nil;
 [objectMapView release], objectMapView = nil;
 [super dealloc];
}

#pragma mark 
#pragma mark -
#pragma mark Enable/Disable Button and Textfield States

-(IBAction) updateSaveButtonState{

 if([objectNameTextField.text isEmptyOrWhitespace])
 {
  [saveButton setEnabled:NO];
 }
 else {
  [saveButton setEnabled:YES];
 }
}

#pragma mark
#pragma mark -
#pragma mark UITextField Delegate - Optional Method Implementations

- (void)textFieldDidEndEditing:(UITextField *)textField{ 

 [textField resignFirstResponder];

 if([textField isEqual:objectNameTextField])
 {
  if(![objectNameTextField.text isEmptyOrWhitespace])
  {
   [object setName:objectNameTextField.text];
  }
  else {
   [object setName:nil];
  }
 }
}

- (void)textFieldDidChange:(NSNotification*)aNotification{
 [self updateSaveButtonState];
}

#pragma mark
#pragma mark -
#pragma mark Core Data Persistance Management Procedures

- (IBAction)save {

 if([objectMapView annotations].count != 0)
 {
  NSLog(@"Cleaning up annotations");
  [objectMapView removeAnnotations:[objectMapView annotations]];
 }

 NSError *error = nil;

 //Double Check that all Object Information is Updated Before Saving
 [self textFieldDidEndEditing:NameTextField];

 if (![managedObjectContext save:&error]) {
  // Handle error
  exit(-1);  // Fail
 }  

 objectMapView.delegate = nil;

 [self.delegate newObjectViewController:self didAddObject:object];
}
- (IBAction)cancel {
 [managedObjectContext deleteObject:object];

 if([objectMapView annotations].count != 0)
 {
  NSLog(@"Trying to clean up %d annotations",[objectMapView annotations].count);
  [objectMapView removeAnnotations:[objectMapView annotations]];
 }

 NSError *error = nil;
 if (![managedObjectContext save:&error]) {
  // Handle error
  exit(-1);  // Fail
 }  

 objectMapView.delegate = nil;

 [self.delegate newObjectViewController:self didAddObject:nil];
}


#pragma mark
#pragma mark -
#pragma mark Location Notification Observer Management

-(void) addLocationObserversAndStartUpdatingLocation{ 
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(locationDeniedNotification) name:@"LOCATION_DENIED_NOTIFICATION" object:nil];
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(newLocationNotification) name:@"NEW_LOCATION_NOTIFICATION" object:nil];
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(locationErrorNotification) name:@"LOCATION_ERROR_NOTIFICATION" object:nil];

 [[MyCLController sharedInstance].locationManager startUpdatingLocation]; 
}
-(void) removeLocationObserversAndStopUpdatingLocation{
 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"LOCATION_DENIED_NOTIFICATION" object:nil];
 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NEW_LOCATION_NOTIFICATION" object:nil];
 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"LOCATION_ERROR_NOTIFICATION" object:nil];

 [[MyCLController sharedInstance].locationManager stopUpdatingLocation];
}

#pragma mark
#pragma mark -
#pragma mark Location Notification Callback Procedures

-(void) newLocationNotification{  
 if(([[MyCLController sharedInstance] locationManager].location != NULL) && ([[MyCLController sharedInstance] locationManager].location != nil))
 {
  [self removeLocationObserversAndStopUpdatingLocation];

  // Add annotation to map 
  CustomMapAnnotation *annotation = [[CustomMapAnnotation alloc] initWithCoordinate:[[MyCLController sharedInstance] locationManager].location.coordinate title:@"Mark Location With Pin"]; 

  [self.objectMapView addAnnotation:annotation];
  [self.objectMapView selectAnnotation:annotation animated:YES];
  [annotation release];
 }
}
-(void) locationErrorNotification{
 [self removeLocationObserversAndStopUpdatingLocation];
}
-(void) locationDeniedNotification{ 
 [self locationErrorNotification];
}


#pragma mark
#pragma mark -
#pragma mark Location Update Procedures

-(IBAction) updateLocationWithPlacemark:(MKPlacemark*)placemark{

 NSDictionary *addressDictionary = [[placemark addressDictionary] retain];
 CLLocationCoordinate2D coordinate = [placemark coordinate];

 //Update Latitude
 [(GeoTag*)[(Location*)[object location] geoTag] setLatitude:[NSNumber numberWithDouble:coordinate.latitude]];

 //Update Longitude
 [(GeoTag*)[(Location*)[object location] geoTag] setLongitude:[NSNumber numberWithDouble:coordinate.longitude]];

 //Update Country
 [object setCountry:[addressDictionary objectForKey:@"CountryCode"]];

 //Update City
 [object setCity:[addressDictionary objectForKey:@"City"]];

 //Update State/Province Initials
 [object setStateOrProvince:[addressDictionary objectForKey:@"State"]];

 //Update ZipCode/PostalCode
 [object setZipCodeOrPostalCode:[addressDictionary objectForKey:@"ZIP"]];

 [addressDictionary release]; 
}

#pragma mark
#pragma mark -
#pragma mark Notification Observers

-(void) addObservers{
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChange:) name:@"UITextFieldTextDidChangeNotification" object:nil];
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(annotationCalloutInfoDidChange:) name:@"MKAnnotationCalloutInfoDidChangeNotification" object:nil];

}
-(void) removeObservers{
 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UITextFieldTextDidChangeNotification" object:nil];
 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"MKAnnotationCalloutInfoDidChangeNotification" object:nil];

}

#pragma mark
#pragma mark -
#pragma mark Custom Annotation Update Notification Handler

-(void) annotationCalloutInfoDidChange:(NSNotification*)aNotification
{
 CustomAnnotation *annotation = (CustomAnnotation*)[aNotification object];
 [self updateLocationWithPlacemark:[annotation placemark]];

 [self updateSaveButtonState];
}

#pragma mark
#pragma mark -
#pragma mark MKMapViewDelegate Optional Implementations

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {

 if (annotation == mapView.userLocation) {
  return nil;
 }

 CustomAnnotationView *annotationView = (CustomAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomAnnotation"];
 if (annotationView == nil) {
  annotationView = [[[CustomAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"CustomAnnotation"] autorelease];
 }

 return annotationView;
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{}

#pragma mark
#pragma mark -
#pragma mark View LifeCycle

-(void) viewDidLoad{

    [super viewDidLoad];

 [self addObservers];

 [self addLocationObserversAndStartUpdatingLocation];
}



@end

此外,这是崩溃日志:

Thread 0 Crashed:
0   libobjc.A.dylib                 0x00003ec0 objc_msgSend + 24
1   UIKit                           0x0005c8b0 -[UIImageView stopAnimating] + 76
2   UIKit                           0x0005c808 -[UIImageView dealloc] + 20
3   CoreFoundation                  0x0003963a -[NSObject release] + 28
4   MapKit                          0x0006b8a4 -[MKAnnotationView dealloc] + 80
5   CoreFoundation                  0x0003963a -[NSObject release] + 28
6   UIKit                           0x0000ab2c -[UIView(Hierarchy) removeFromSuperview] + 592
7   UIKit                           0x0005ca1c -[UIView dealloc] + 232
8   MapKit                          0x0003a814 -[MKOverlayView dealloc] + 804
9   CoreFoundation                  0x0003963a -[NSObject release] + 28
10  UIKit                           0x0000ab2c -[UIView(Hierarchy) removeFromSuperview] + 592
11  UIKit                           0x0005ca1c -[UIView dealloc] + 232
12  UIKit                           0x000cb870 -[UIScrollView dealloc] + 284
13  MapKit                          0x000699bc -[MKScrollView dealloc] + 88
14  CoreFoundation                  0x0003963a -[NSObject release] + 28
15  UIKit                           0x0000ab2c -[UIView(Hierarchy) removeFromSuperview] + 592
16  UIKit                           0x000cb4a0 -[UIScrollView removeFromSuperview] + 68
17  UIKit                           0x0005ca1c -[UIView dealloc] + 232
18  CoreFoundation                  0x0003963a -[NSObject release] + 28
19  UIKit                           0x0000ab2c -[UIView(Hierarchy) removeFromSuperview] + 592
20  UIKit                           0x0005ca1c -[UIView dealloc] + 232
21  MapKit                          0x00017794 -[MKMapView dealloc] + 1384
22  CoreFoundation                  0x0003963a -[NSObject release] + 28
23  UIKit                           0x0000ab2c -[UIView(Hierarchy) removeFromSuperview] + 592
24  UIKit                           0x0005ca1c -[UIView dealloc] + 232
25  CoreFoundation                  0x0003963a -[NSObject release] + 28
26  UIKit                           0x0000ab2c -[UIView(Hierarchy) removeFromSuperview] + 592
27  UIKit                           0x0005ca1c -[UIView dealloc] + 232
28  CoreFoundation                  0x0003963a -[NSObject release] + 28
29  UIKit                           0x0000ab2c -[UIView(Hierarchy) removeFromSuperview] + 592
30  UIKit                           0x0005ca1c -[UIView dealloc] + 232
31  CoreFoundation                  0x0003963a -[NSObject release] + 28
32  UIKit                           0x0000ab2c -[UIView(Hierarchy) removeFromSuperview] + 592
33  UIKit                           0x0005ca1c -[UIView dealloc] + 232
34  CoreFoundation                  0x0003963a -[NSObject release] + 28
35  Foundation                      0x00047990 NSPopAutoreleasePool + 238
36  QuartzCore                      0x0001e0fc run_animation_callbacks(double, void*) + 600
37  QuartzCore                      0x0001de64 CA::timer_callback(__CFRunLoopTimer*, void*) + 156
38  CoreFoundation                  0x000574bc CFRunLoopRunSpecific + 2192
39  CoreFoundation                  0x00056c18 CFRunLoopRunInMode + 44
40  GraphicsServices                0x0000436c GSEventRunModal + 188
41  UIKit                           0x00003c28 -[UIApplication _run] + 552
42  UIKit                           0x00002228 UIApplicationMain + 960
43  TestApp                         0x0000244a main (main.m:14)
44  TestApp                         0x000021d4 start + 44

1 个答案:

答案 0 :(得分:3)

0   libobjc.A.dylib                 0x00003ec0 objc_msgSend + 24
1   UIKit                           0x0005c8b0 -[UIImageView stopAnimating] + 76
2   UIKit                           0x0005c808 -[UIImageView dealloc] + 20

您的应用程序崩溃是因为您在发布UIImageView后尝试调用[UIImageView stopAnimating]。