繁体   English   中英

EXC_BAD_ACCESS 第二次启动我的应用程序并调用 reloadTable

[英]EXC_BAD_ACCESS second time I start my application and call reloadTable

注意:问题不在此代码中,但 EXC_BAD_ACCESS 的答案是@strange 所说的。

在调用 viewForHeaderInSection 方法后,我得到了这个 EXC_BAD_ACCESS,伙计们,我已经调试了过去几个小时,所以我的表第一次在这里加载是被调用的方法的顺序。

注意:我有两个部分,每个部分只有一行。

  1. numberOfSectionsInTableView
  2. viewForHeaderInSection(用于第 1 节)
  3. heightForHeaderInSection(用于第 1 节)
  4. numberOfRowsInSection(用于第 1 节)
  5. heightForRowAtIndexPath(对于第 1 节,第 0 行)
  6. viewForHeaderInSection(用于第 0 节)
  7. heightForHeaderInSection(用于第 0 节)
  8. numberOfRowsInSection(对于第 0 节)
  9. heightForRowAtIndexPath(对于第 0 节,第 0 行)
  10. cellForRowAtIndexPath(对于第 0 行,第 0 行)
  11. cellForRowAtIndexPath(对于第 1 行,第 0 行)
  12. viewForHeaderInSection(用于第 0 节)
  13. viewForHeaderInSection(用于第 1 节)

然后我的表格会正确显示。

现在我打电话

 [self.tableView reloadTable]

上述所有 13 个方法都以相同的顺序调用,但在数字 13 之后,我的代码转到下一行的 main 方法

 int retVal = UIApplicationMain(argc, argv, nil, nil); 

显示 EXC_BAD_ACCESS。

我在环境变量中启用了 NSZombie 但没有帮助,我尝试了分配和僵尸检测,但无法弄清楚任何事情。

任何帮助都会很有用。

编辑:我在 header 部分有一个 customView,我在 cell.contentView 上添加了一个 customView

EDIT2: 抱歉各位,reloadTable 得到正确执行,这个异常来自其他地方,我仍在试图找出从哪里来。

EDIT3:嗨,我有更多信息要分享,当我在模拟器上全新安装应用程序时,这意味着从模拟器中删除应用程序并从 xcode 全新安装它一切正常,现在全新安装后我停止通过 Xcode 并再次运行Xcode,我收到 NSZombie 的以下错误消息

 [CALayer retainCount]: message sent to deallocated instance 0x19384fd0

在我重新加载表之后的某个地方,我完全不确定那个错误来自哪里。

(gdb) po 0x19384fd0 2011-05-01 07:08:06.194 Doot[51635:207] * -[CALayer respondsToSelector:]:消息发送到已释放实例 0x19384fd0

程序收到信号 SIGTRAP,跟踪/断点陷阱。 0x012f1657 in forwarding () 正在调试的程序在从 GDB 调用的 function 中发出信号。 GDB 已将上下文恢复到调用前的状态。 要更改此行为,请使用“set unwindonsignal off” 对包含 function (_NSPrintForDebugger) 的表达式的评估将被放弃。 (gdb) 回溯

0 0x012f1657 在转发()

1 0x012f1522 在forwarding_prep_0_ ()

2 0x012bf990 在 CFGetRetainCount()

3 0x000d9dc1 在 CA::release_root_if_unused ()

4 0x0015830f 在 x_hash_table_remove_if ()

5 0x000da246 在 CA::Transaction::commit ()

6 0x000da46d 在 CA::Transaction::observer_callback ()

7 0x0136189b 在CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION ()

8 0x012f66e7 在 __CFRunLoopDoObservers ()

9 0x012bf1d7 在 __CFRunLoopRun()

10 0x012be840 在 CFRunLoopRunSpecific()

11 0x012be761 在 CFRunLoopRunInMode()

12 0x01ec71c4 在 GSEventRunModal()

13 0x01ec7289 在 GSEventRun ()

14 0x004a1c93 在 UIApplicationMain ()

15 0x000025d4 在 main (argc=1, argv=0xbffffef2c) 在 main.m:13

之后我得到这个异常的流程序列。

我正在运行异步nsurlconnection,一旦我在connectionDidFinishLoading中获得响应,我就会将该数据保存到数据库中,通过调用一个方法让我们在我的databasehelper class中调用它saveData,在saveData方法中我设置了一个boolean变量

   dataSaved = YES 

我的两个视图控制器(其中有一个表)正在观察这个 boolean 变量,一旦变量设置为 YES,这两个视图 controller 就会收到通知

 (void)observeValueForKeyPath:(NSString *)keyPath
                  ofObject:(id)object
                    change:(NSDictionary *)change
                   context:(void *)context 

我重新加载表,一旦重新加载表完成,是的,它完成了,控制返回到 connectionDidFinishLoading 然后它正确存在然后繁荣我得到这个异常,我不知道这个异常来自我的代码的哪一行未来。

另外有趣的是,如果我没有设置 boolean 标志 dataSaved = YES 则不会调用 observeValueForKeyPath 并且我的表不会重新加载,在这种情况下我的异常不会崩溃。 这就是为什么最初我认为这是由于表的重新加载,实际上这仍然是正确的。

我正在输入一些代码来解释流程

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
   [localNavigationController 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;

}

登录页面控制器.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 //当这个得到初始化我做

 [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];

}

后端助手.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;

}

第一视图控制器.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];
        }
}
}

您需要向我们展示如何以及何时创建自定义视图。 请注意:您应该始终在每次调用 viewForHeaderInSection 方法时创建“新”自定义视图,然后在返回时自动释放它们,或者在调用 [tableView reloadData] 之前为每个“标题”分配和创建自定义视图,然后稍后释放它们。 您看到的这个错误很可能是由于您使用“自动释放”返回自定义视图,然后在稍后尝试重新使用 object。

当您尝试释放已发布的 object 或尝试访问已发布的 object(现在是指向 memory 其他部分的悬空指针)时,通常会发生此错误。 例如,这将导致此问题:

  1. 您可以像这样在“viewDidLoad”中创建自定义视图:

    myView = [[CustomView alloc] initWithFrame....]; ……

  2. 在 viewForHeaderInSection 中,您将像这样返回它:

    返回 [myView 自动释放];

或者是这样的:

viewDidLoad:
myView = [[CustomView alloc] initWithFrame....];

....


cellForRow:
cell.contentView = myView;
[myView autorelease];

然后再次返回 viewForHeaderInSection: return myView;

换句话说,这与您如何分配它、您如何“重新使用它”或您如何可能自动释放它有关。 只需确保您事先创建此视图并在完整的 viewController 被释放时释放(或在下次调用 [tableView reloadData] 之前),或者在每次调用 viewForHeaderInSection 时创建一个新的自定义视图,如下所示:

- (UIView*) viewForHeaderInSection:
return [[[CustomView alloc] init] autorelease];

可能您返回的 noOfSection 超出了您的需要。 看看是不是这样。 尝试检查有多少部分。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM