[NSCFString viewWillAppear:]: unrecognized selector sent to instance on iPhone 3G but not on simulator or iPhone 4
I've been looking for a solution for nearly 4 hours but I've been unable to find anything...
I've got an application with two tabs. The first one contains a Navigation controller, and the second a MKMapView
. Everything is properly linked onto IB. This works fine on the simulator and on an iPhone4, but if I try on an iPhone 3G (I tried on two different actually), I've got a memory error.
Here is the stack trace :
2011-05-04 11:38:44.652 GeoSocial[8191:307] -[NSCFString viewWillAppear:]: unrecognized selector sent to instance 0x3e7b7040
2011-05-04 11:38:44.901 GeoSocial[8191:307] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString viewWillAppear:]: unrecognized selector sent to instance 0x3e7b7040'
*** Call stack at first throw:
(
0 CoreFoundation 0x3759dc7b __exceptionPreprocess + 114
1 libobjc.A.dylib 0x32d9bee8 objc_exception_throw + 40
2 CoreFoundation 0x3759f3e3 -[NSObject(NSObject) doesNotRecognizeSelector:] + 98
3 CoreFoundation 0x37544467 ___forwarding___ + 506
4 CoreFoundation 0x37544220 _CF_forwarding_prep_0 + 48
5 UIKit 0x3597b7bc -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 220
6 UIKit 0x3597b6d4 -[UITabBarController transitionFromViewController:toViewController:] + 40
7 UIKit 0x3597ad40 -[UITabBarController _setSelectedViewController:] + 256
8 UIKit 0x35a83c4c -[UITabBarController setSelectedViewController:] + 20
9 UIKit 0x35a84890 -[UITabBarController _tabBarItemClicked:] + 316
10 CoreFoundation 0x37542a43 -[NSObject(NSObject) performSelector:withObject:withObject:] + 26
11 UIKit 0x35902f20 -[UIApplication sendAction:to:from:forEvent:] + 136
12 UIKit 0x35902e88 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 40
13 UIKit 0x35b69ee0 -[UITabBar _sendAction:withEvent:] + 424
14 CoreFoundation 0x37542a43 -[NSObject(NSObject) performSelector:withObject:withObject:] + 26
15 UIKit 0x35902f20 -[UIApplication sendAction:to:from:forEvent:] + 136
16 UIKit 0x35902e88 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 40
17 UIKit 0x35902e50 -[UIControl sendAction:to:forEvent:] + 52
18 UIKit 0x35902aa0 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 536
19 UIKit 0x35947340 -[UIControl sendActionsForControlEvents:] + 24
20 UIKit 0x35b66568 -[UITabBar(Static) _buttonUp:] + 116
21 CoreFoundation 0x37542a43 -[NSObject(NSObject) performSelector:withObject:withObject:] + 26
22 UIKit 0x35902f20 -[UIApplication sendAction:to:from:forEvent:] + 136
23 UIKit 0x35902e88 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 40
24 UIKit 0x35902e50 -[UIControl sendAction:to:forEvent:] + 52
25 UIKit 0x35902aa0 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 536
26 UIKit 0x359035cc -[UIControl touchesEnded:withEvent:] + 460
27 UIKit 0x358f4eb0 -[UIWindow _sendTouchesForEvent:] + 588
28 UIKit 0x358f44e4 -[UIWindow sendEvent:] + 396
29 UIKit 0x358d7c9c -[UIApplication sendEvent:] + 452
30 UIKit 0x358d73b4 _UIApplicationHandleEvent + 6824
31 GraphicsServices 0x33e77c88 PurpleEventCallback + 1048
32 CoreFoundation 0x3752f5cb __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 28
33 CoreFoundation 0x3752f589 __CFRunLoopDoSource1 + 164
34 CoreFoundation 0x37521835 __CFRunLoopRun + 580
35 CoreFoundation 0x3752150b CFRunLoopRunSpecific + 226
36 CoreFoundation 0x37521419 CFRunLoopRunInMode + 60
37 GraphicsServices 0x33e76d24 GSEventRunModal + 196
38 UIKit 0x3591d57c -[UIApplication _run] + 588
39 UIKit 0x3591a558 UIApplicationMain + 972
40 GeoSocial 0x00002ec1 main + 72
41 GeoSocial 0x00002e74 start + 40
)
terminate called after throwing an instance of 'NSException'
Somthing else is kinda weird : everytime I launch the application, and whatever is the device, I still have the same address for the instance (0x3e7b7040).
I tried debugging step by step. The viewDidLoad
method runs fine, but right after it (after a few steps into the assembly mode of xCode) the exception is thrown.
Does anyone have an idea or a lead to debug it?
Here is the concerned view controller code :
LastLocViewController.h
//
// SecondViewController.h
// LocateMe
//
// Created by Hugo Briand on 07/04/11.
// Copyright 2011 Neotiq. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "LocateMeAppDelegate.h"
@interface LastLocViewController : UIViewController <CLLocationManagerDelegate, AdBannerDelegate> {
IBOutlet MKMapView *mapView;
IBOutlet ADBannerView *adBanView;
}
@property (nonatomic, retain) IBOutlet MKMapView *mapView;
@property (nonatomic, retain) IBOutlet UIView *contentView;
@end
LastLocViewController.m
//
// SecondViewController.m
// LocateMe
//
// Created by Hugo Briand on 07/04/11.
// Copyright 2011 Neotiq. All rights reserved.
//
#import "LastLocViewController.h"
#import "CLContact.h"
#import "CLContactManager.h"
@interface LastLocViewController()
-(void)recenterRegion;
@end
@implementation LastLocViewController
@synthesize mapView;
@synthesize contentView;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
if (![CLLocationManager locationServicesEnabled]) {
UIAlertView *error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil) message:NSLocalizedString(@"You need to enable location services for this application in your Settings", nil) delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[error show];
[error release];
}
NSMutableArray *locations = [[NSMutableArray alloc] init];
LocateMeAppDelegate *del = (LocateMeAppDelegate *) [[UIApplication sharedApplication] delegate];
for (NSArray *ac in [[del.contactManager clContacts] allValues]) {
for (CLContact *c in ac) {
if (c.coordinate.latitude !=0 || c.coordinate.longitude != 0) {
[locations addObject:c];
}
}
}
[mapView addAnnotations:[NSArray arrayWithArray:locations]];
[locations release];
[self recenterRegion];
#ifdef ADD_ENABLED
// Configuring ads
if (adBanView != del.adBanner) {
adBanView = del.adBanner;
del.adBanDelegate = self;
}
[self layoutForCurrentOrientation:NO];
#else
[adBanView removeFromSuperview];
#endif
}
-(void)layoutForCurrentOrientation:(BOOL)animated
{
#ifdef ADD_ENABLED
LocateMeAppDelegate *del = (LocateMeAppDelegate *)[[UIApplication sharedApplication] delegate];
ADBannerView *sharedAdBan = del.adBanner;
CGFloat animationDuration = animated ? 0.2f : 0.0f;
// by default content consumes the entire view area
CGRect contentFrame = self.view.bounds;
// the banner still needs to be adjusted further, but this is a reasonable starting point
// the y value will need to be adjusted by the banner height to get the final position
CGPoint bannerOrigin = CGPointMake(CGRectGetMinX(contentFrame), CGRectGetMaxY(contentFrame));
CGFloat bannerHeight = 0.0f;
// First, setup the banner's content size and adjustment based on the current orientation
sharedAdBan.currentContentSizeIdentifier = (&ADBannerContentSizeIdentifierPortrait != nil) ? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifier320x50;
bannerHeight = sharedAdBan.bounds.size.height;
// Depending on if the banner has been loaded, we adjust the content frame and banner location
// to accomodate the ad being on or off screen.
// This layout is for an ad at the bottom of the view.
if(sharedAdBan.bannerLoaded)
{
contentFrame.size.height -= bannerHeight;
bannerOrigin.y -= bannerHeight;
}
else
{
bannerOrigin.y += bannerHeight;
}
// And finally animate the changes, running layout for the content view if required.
[UIView animateWithDuration:animationDuration
animations:^{
mapView.frame = contentFrame;
[mapView layoutIfNeeded];
sharedAdBan.frame = CGRectMake(bannerOrigin.x, bannerOrigin.y, sharedAdBan.frame.size.width, sharedAdBan.frame.size.height);
}];
#endif
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (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];
#ifdef ADD_ENABLED
LocateMeAppDelegate *del = (LocateMeAppDelegate *)[[UIApplication sharedApplication] delegate];
[del.adBanner removeFromSuperview];
del.adBanDelegate = nil;
#endif
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
#ifdef ADD_ENABLED
LocateMeAppDelegate *del = (LocateMeAppDelegate *)[[UIApplication sharedApplication] delegate];
if (adBanView != del.adBanner) {
adBanView = del.adBanner;
del.adBanDelegate = self;
}
[self layoutForCurrentOrientation:NO];
#endif
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSLog(@"CLContactLocSyncVC viewWillDisappear");
#ifdef ADD_ENABLED
LocateMeAppDelegate *del = (LocateMeAppDelegate *)[[UIApplication sharedApplication] delegate];
[del.adBanner removeFromSuperview];
del.adBanDelegate = nil;
[del.currentSyncLoc setDelegate:nil];
#endif
}
-(void)recenterRegion {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CLLocationDegrees maxLat=-90;
CLLocationDegrees minLat=90;
CLLocationDegrees maxLon=-180;
CLLocationDegrees minLon=180;
for(id ann in [mapView annotations]) {
if ([ann isKindOfClass:[CLContact class]]) {
minLat = MIN(minLat, [ann coordinate].latitude);
minLon = MIN(minLon, [ann coordinate].longitude);
开发者_高级运维 maxLat = MAX(maxLat, [ann coordinate].latitude);
maxLon = MAX(maxLon, [ann coordinate].longitude);
}
}
CLLocationDegrees spLat = MIN(MAX(ABS([mapView userLocation].coordinate.latitude-minLat),
ABS([mapView userLocation].coordinate.latitude-maxLat))*2*1.1, 90);
CLLocationDegrees spLon = MIN(MAX(ABS([mapView userLocation].coordinate.longitude-minLon),
ABS([mapView userLocation].coordinate.longitude-maxLon))*2*1.1, 180);
MKCoordinateSpan sp = MKCoordinateSpanMake(spLat, spLon);
MKCoordinateRegion reg = MKCoordinateRegionMake([mapView userLocation].coordinate, sp);
@try {
[mapView setRegion:reg animated:YES];
}
@catch (NSException *e) {
NSLog(@"caught invalid argument exception on setRegion, continuing : %@", [e description]);
}
[self performSelector:@selector(recenterRegion) withObject:nil afterDelay:10.0];
[pool release];
}
- (void)dealloc
{
#ifdef ADD_ENABLED
LocateMeAppDelegate *del = (LocateMeAppDelegate *)[[UIApplication sharedApplication] delegate];
[del.adBanner removeFromSuperview];
del.adBanDelegate = nil;
#endif
[super dealloc];
}
@end
Thanks in advance !
EDIT
I finally got it after listening to Andrew's second advice. The issue was in the viewDidLoad
method. This block :
NSMutableArray *locations = [[NSMutableArray alloc] init];
LocateMeAppDelegate *del = (LocateMeAppDelegate *) [[UIApplication sharedApplication] delegate];
for (NSArray *ac in [[del.contactManager clContacts] allValues]) {
for (CLContact *c in ac) {
if (c.coordinate.latitude !=0 || c.coordinate.longitude != 0) {
[locations addObject:c];
}
}
}
[mapView addAnnotations:[NSArray arrayWithArray:locations]];
[locations release];
was incorrect if I had no location in the locations array. Somehow it led to a crash. I added a check on the size of the array and that made it.
Thanks for your reply Andrew !
I'd recommend running your code in Instruments using the NSZombie target. Alternatively you may try running with the NSZombieEnabled environment variable set in your application executable options.
Doing this should help you get to the root of the problem.
Other than that, try stepping away for a few hours and come back to it with a fresh head and re-question all your existing assumptions.
精彩评论