2009-11-07 64 views
1

因此,在過去的幾天中,我一直在努力理解如何實現帶有一些自定義註釋的簡單MKMapView,而不會在應用程序中崩潰。不幸的是,我一直無法確定我做錯了什麼,並且在這個過程中變得越來越沮喪。如何避免MKMapKit iPhone上的相關崩潰

我想要完成的應該是相對簡單的。我正在嘗試創建一個新對象,並附帶一個與之關聯的位置。爲此,我有一個用於創建對象的視圖控制器。我希望用戶能夠隨時取消視圖控制器,如果他們願意的話,但爲了保存對象,他們必須首先提供一個位置和一個名稱。該名稱將通過UITextField獲取,而位置將通過MKMapView獲取。

因此,這裏是發生了什麼......每當我打開新的對象視圖控制器,它會更新位置和whatnot。如果我嘗試點擊取消,它會崩潰。爲了簡化問題,我刪除了更新位置和移動註釋引腳的代碼,因此您不會在下面看到。

下面是我使用的一些代碼,以及崩潰後遇到的堆棧跟蹤示例。任何幫助你可以提供將不勝感激。謝謝!

之前,我告訴你我的代碼,這裏是堆棧跟蹤我結束了:

堆棧跟蹤崩潰

#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 

,以及最後但並非最不重要,releva我的新對象視圖控制器的NT部分:

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 
+0

快速提示...當我說我刪除了用於移動註釋視圖和更新位置的代碼時,我在測試代碼之前執行了此操作,而不是之後執行此操作,所以我不會留下任何內容,只是想達到可以取消該視圖不會崩潰,然後我會擔心其他細節。 – TheAggie 2009-11-07 22:13:37

回答

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

您的應用程序崩潰是因爲你嘗試在釋放UIImageView後調用[UIImageView stopAnimating]。

+1

哈哈,是的,我在發佈這篇文章後不久就想到了,但完全忘了回來。雖然謝謝:) – TheAggie 2009-12-10 17:46:16