因此,在过去的几天里,我一直在努力了解如何使用一些自定义注释实现简单的 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
答案 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]。