EXC_BAD_ACCESS second time I start my application and call reloadTable
NOTE: THE PROBLEM IS NOT IN THIS CODE, BUT THE ANSWER FOR EXC_BAD_ACCESS is what @strange said.
I am getting this EXC_BAD_ACCESS after viewForHeaderInSection method gets called, guys I have been debugging this for last couple of hours now, so the first time my table gets loaded here is the sequence of the method that gets called.
NOTE: I have two sections each with one row only.
- numberOfSectionsInTableView
- viewForHeaderInSection (for section 1)
- heightForHeaderInSection (for section 1)
- numberOfRowsInSection (for section 1)
- heightForRowAtIndexPath (for section 1, row 0)
- viewForHeaderInSection (for section 0)
- heightForHeaderInSection (for section 0)
- numberOfRowsInSection (for section 0)
- heightForRowAtIndexPath (for section 0, row 0)
- cellForRowAtIndexPath (for section 0, row, 0)
- cellForRowAtIndexPath (for section 1, row, 0)
- viewForHeaderInSection (for section 0)
- viewForHeaderInSection (for section 1)
And then my table get displayed properly.
Now I call
[self.tableView reloadTable]
All the above 13 methods get called in the same sequence but after the number 13 my code goes to main method on the following line
int retVal = UIApplicationMain(argc, argv, nil, nil);
showing the EXC_BAD_ACCESS.
I enabled NSZombie in the environment variable but no help, i tried allocation and zombie instrumentation, but couldn't figure out any thing.
Any help will be useful.
EDIT: I have a customView for section header and on I am adding a customView on cell.contentView
EDIT2: Sorry guys for the confusion, the reloadTable gets executed properly this exception is coming from some other place, I am still trying to find out from where.
EDIT3: Hi I have some more information to share, when I fresh install the application on the simulator, meaning deleting the app from the simulator and installing it fresh from xcode everything works fine, now after fresh install I stop through Xcode and run again through Xcode, i get the following error message with NSZombie
[CALayer retainCount]: message sent to deallocated instance 0x19384fd0
somewhere after i reloadTable, I am exactly not sure where that error comes.
(gdb) po 0x19384fd0 2011-05-01 07:08:06.194 Doot[51635:207] * -[CALayer respondsToSelector:]: message sent to deallocated instance 0x19384fd0
Program received signal SIGTRAP, Trace/breakpoint trap. 0x012f1657 in forwarding () The program being debugged was signaled while in a function called from GDB. GDB has restored the context to what it was before the call. To change this behavior use "set unwindonsignal off" Evaluation of the expression containing the function (_NSPrintForDebugger) will be abandoned. (gdb) backtrace
0 0x012f1657 in forwarding ()
1 0x012f1522 in forwarding_prep_0_ ()
2 0x012bf990 in CFGetRetainCount ()
3 0x000d9dc1 in CA::release_root_if_unused ()
4 0x0015830f in x_hash_table_remove_if ()
5 0x000da246 in CA::Transaction::commit ()
6 0x000da46d in CA::Transaction::observer_callback ()
7 0x0136189b in CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION ()
8 0x012f66e7 in __CFRunLoopDoObservers ()
9 0x012bf1d7 in __CFRunLoopRun ()
10 0x012be840 in CFRunLoopRunSpecific ()
11 0x012be761 in CFRunLoopRunInMode ()
12 0x01ec71c4 in GSEventRunModal ()
13 0x01ec7289 in GSEventRun ()
14 0x004a1c93 in UIApplicationMain ()
15 0x000025d4 in main (argc=1, argv=0xbfffef2c) at main.m:13
Sequence of flow after which i get this exception.
I am running async nsurlconnection, once i get back the response in connectionDidFinishLoading, i save that data to the database, by calling a method let us call it saveData in my databasehelper class, in the saveData method I set a boolean variable
dataSaved = YES
Two of my view controller(having a table in it) are observing this boolean variable, and as soon as the variable set to YES, those two view controller get notified on their
(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
I reload the table, once the reload table is done, YES it is done, the control goes back to connectionDidFinishLoading and then it exist properly and then boom I get this exception, i have freaking no idea from which line of my code this exception is coming.
Also what is interesting is, if i don't set that boolean flag dataSaved = YES then the observeValueForKeyPath doesn't get called and my table doesn't reload, in that case my exception doesn't crash. that's why initially i thought it is due to the reload of the table, and actually that can be still true.
I am putting some of my code to explain the flow
MyAppDelegate.m
if ([facebook isSessionValid]) {
locationHelper = [LocationHelper sharedInstance];
tabBarController = [[AppTabBarController createTabBarController:self] retain];
[self.window addSubview:tabBarController.view];
}else{
loginPageController = [[LoginPageController alloc]initWithFacebook:facebook];
loginNavigationController = [[UINavigationController alloc] initWithRootViewController:loginPageController];
loginNavigationController.navigationBar.barStyle = UIBarStyleBlack;
loginPageController.navigationItem.hidesBackButton = YES;
[self.window addSubview:loginNavigationController.view];
[loginPageController release];
//[localNavigationController release];
}
AppTabBarController.m
+ (UITabBarController*) createTabBarController:(id)delegate {
UINavigationController *localNavigationController;
NSMutableArray *localControllersArray = [[NSMutableArray alloc] initWithCapacity:2];
FirstViewController *firstTabController = [[FirstViewController alloc]init];
localNavigationController = [[UINavigationController alloc]
initWithRootViewController: firstTabController];
localNavigationController.navigationBar.barStyle = UIBarStyleBlack;
[localControllersArray addObject:localNavigationController];
// release since we are done with this for now they are not part of the array
[localNavigationCo开发者_C百科ntroller release];
[firstTabController release];
FirstViewController *secondTabController = [[FirstViewController alloc]init];
localNavigationController = [[UINavigationController alloc]
initWithRootViewController: secondTabController];
localNavigationController.navigationBar.barStyle = UIBarStyleBlack;
[localControllersArray addObject:localNavigationController];
// release since we are done with this for now they are not part of the array
[localNavigationController release];
[secondTabController release];
UITabBarController* tabBarController = [[[UITabBarController alloc] init ] autorelease];
// load up our tab bar controller with the view controllers
tabBarController.viewControllers = localControllersArray;
tabBarController.delegate = delegate;
// release the array because the tab bar controller now has it
[localControllersArray release];
return tabBarController;
}
LoginPageController.m
-(id)initWithFacebook:(Facebook*)facebookInstance{
self.facebook = facebookInstance;
return self;
}
- (IBAction)fbButtonClick:(id)sender {
NSArray *permissions;
permissions = [NSArray arrayWithObjects:
@"email", nil];
[facebook authorize:permissions delegate:self];
}
- (void)fbDidLogin {
NSLog(@"Inside LoginpageController fbDidLogin");
//NSLog(@"Access Token is %@", facebook.accessToken );
//NSLog(@"Expiration Date is %@", facebook.expirationDate );
// Store the value in the NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:facebook.accessToken forKey:ACCESS_TOKEN_KEY];
[defaults setObject:facebook.expirationDate forKey:EXPIRATION_DATE_KEY];
[defaults synchronize];
// This is the best place to get user details because here we know that user has already logged in
[facebook requestWithGraphPath:@"me" andDelegate:self];
}
- (void)request:(FBRequest *)request didLoad:(id)result {
NSLog(@"Inside LoginPageController didLoad");
//NSLog(@"request returns user data %@",result);
MyAppDelegate* myAppDelegate = (MyAppDelegate*)[[UIApplication sharedApplication]delegate];
[self.navigationController pushViewController:[AppTabBarController myAppDelegate] animated:YES];
}
LocationHelper.m //When this get initialize i do
[self.locationManager startUpdatingLocation];
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
//if the time interval returned from core location is more than two minutes we ignore it because it might be from an old session
[self.locationManager stopUpdatingLocation];
self.currentLocation = newLocation;
[self updateDataBase];
}
-(void)updateDataBase{
NSLog(@"Inside updateDataBase");
BackendHelper *backendHelper = [BackendHelper sharedInstance];
[backendHelper getData];
}
BackendHelper.m
-(void) getData{
NSURL *getURL = [NSURL URLWithString: @"my url"];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
//add our HTTP headers and URL
[request setValue: @ "plain/text" forHTTPHeaderField : @"Content-Type"];
[request setHTTPMethod:@"GET"];
[request setURL : getURL];
// Use NSURLConnection to asynchronously download the data. This means the main thread will not
// be blocked - the application will remain responsive to the user.
//
// IMPORTANT! The main thread of the application should never be blocked!
// Also, avoid synchronous network access on any thread.
//
NSURLConnection* urlConnection =
[[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// check for HTTP status code for proxy authentication failures
// anything in the 200 to 299 range is considered successful,
// also make sure the MIMEType is correct:
//
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ((([httpResponse statusCode]/100) == 2) && [[response MIMEType] isEqual:@"text/html"]) {
NSLog(@"Response status code is:%d", [httpResponse statusCode]);
self.responseData = [[NSMutableData alloc] init];
} else {
NSLog(@"didReceiveResponse error");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(@"didReceiveData");
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"didFailWithError");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"connectionDidFinishLoading");
[self handleResponseData:responseData];
[self.responseData release];
self.responseData = nil;
}
- (void) handleResponseData:(NSData*)data {
NSString * strResult = [[NSString alloc] initWithData: data encoding:NSUTF8StringEncoding];
[[DatabaseHelper sharedInstance] saveData: strResult];
[strResult release];
}
-(void) saveData:(NSString*) strResult{
// save data to the database
dataSaved = YES;
}
FirstViewController.m
- (void)viewDidLoad
{
[databaseHelper addObserver:self forKeyPath:@"dataSaved" options:NSKeyValueObservingOptionNew context:nil];
uiTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 372) style:UITableViewStylePlain];
uiTableView.dataSource = self;
uiTableView.delegate = self;
uiTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"doot_background.png"]];
self.uiTableView.backgroundColor = background;//[UIColor blackColor];
uiTableView.scrollEnabled = NO;
[background release];
[self.view addSubview:uiTableView];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if([keyPath isEqualToString:@"dataSaved"]){
DatabaseHelper *databaseHelperObject = (DatabaseHelper*)object;
if(databaseHelperObject.dootUpdated){
//getData from the database
[self.uiTableView reloadData];
}
}
}
You need to show us how and when that custom view is being created. Please note: you should always create 'new' custom views each time that method is called viewForHeaderInSection and then autorelease them when returning OR allocate and create custom views for each 'header' before calling [tableView reloadData] and then release them later. This error you're seeing is most probably due to yourself returning the customview with an 'autorelease' and then at some point later trying to re-use the object.
This error usually happens when you try to release an object which has already been released or trying to access a released object which now is a dangling pointer pointing to some other part of memory. For example, this would cause this problem:
You create the custom view in 'viewDidLoad' like this:
myView = [[CustomView alloc] initWithFrame....]; ....
In viewForHeaderInSection you are returning it like this:
return [myView autorelease];
OR something like this:
viewDidLoad:
myView = [[CustomView alloc] initWithFrame....];
....
cellForRow:
cell.contentView = myView;
[myView autorelease];
and then returning it again viewForHeaderInSection: return myView;
In other words, this has something to do with how you're allocating it, how you're 're-using it' or how you're possibly autoreleasing it. Just make sure you either create this view before hand and release when the complete viewController gets deallocated (or before the next time you call [tableView reloadData]) OR you create a new custom view on each call to viewForHeaderInSection like this:
- (UIView*) viewForHeaderInSection:
return [[[CustomView alloc] init] autorelease];
may be you returning noOfSection more than you need. see if this is the case. Try to check how many sections are there.
精彩评论