views:

176

answers:

2

I'm facing some sort of memory related issue I cannot figure out.

I have one summary view that lists some settings and a detail view where you can edit each setting.

In the summary view I have a tableview populated by an array (settingArray) of settings which in turn is loaded from a core data repository.

//  SettingsViewController.h
@interface SettingsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
    NSMutableArray *settingArray;
}
@property (nonatomic, retain) NSMutableArray *settingArray;

//  SettingsViewController.m
- (void)viewWillAppear:(BOOL)animated {
    [self setSettingArray:[DataHelper searchObjectsInContext:@"Sections" :nil :@"Id" :YES :managedObjectContext]];
}

This array of NSManaged objects is used to assign values to a custom UITableViewCell which has two labels: title and description.

//  SettingsViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    […]
    [cell.titleLabel setText:[[settingArray objectAtIndex:indexPath.row] valueForKey:@"Title"]]; 
    [cell.descriptionLabel setText:[[settingArray objectAtIndex:indexPath.row] valueForKey:@"Description"]]; 
    […]
}

When the user clicks on a row, this loads a detail view where you can edit the values and save them to the database. The summary view passes the detail view an NSManagedObject reference (settingObject) in order to know what record in the core data database was selected and must be updated.

//  SettingsViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (settingsDetailViewController == nil) {
     settingsDetailViewController = [[SettingsDetailViewController alloc] initWithNibName:@"SettingsDetailView" bundle:nil];
    }

    // Pass corresponding settingArray object to detail view in the settingObject variable
    settingsDetailViewController.settingObject = [settingArray objectAtIndex:indexPath.row];
    […]
}

In the detail view, the user can modify some values and then save the modified core data object in the database.

//  SettingsDetailViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Update current setting in database
    [self.settingObject setValue:[tableView cellForRowAtIndexPath:indexPath].textLabel.text forKey:@"Description"];
}

The problem is that once the value is updated in the detail view in this NSManagedObject, when the tableview information in the summary view is reloaded, I get a EXC_BAD_ACCESS exactly in the point where the label information is read from the settingArray.

//  SettingsViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    [cell.titleLabel setText:[[settingArray objectAtIndex:indexPath.row] valueForKey:@"Title"]]; 

    // HERE IS WHERE THE ERROR OCCURS IN THE SECOND PASS
    [cell.descriptionLabel setText:[[settingArray objectAtIndex:indexPath.row] valueForKey:@"Description"]]; 
    […]
}

I guess it's related to the release of the settingArray or settingObject being used, but I tried different approaches and no solution yet. All variables are declared in the corresponding .h, properties are added using nontoxic and retain, the accessors are synthesized in the .m and the objects are released in the dealloc function. According to the Cocoa memory management guidelines it should work.

The funny thing is that other parts of my code use identical arrays and pass identical objects with no problems whatsoever.

Any hints please?

A: 

It's hard to pinpoint the problem without the complete source. Some items you can try:

  • Make sure the "settingObject" property in SettingsDetailViewController.h is declared as a "retain". Maybe you forgot the "retain", but released this instance in the dealloc method?
  • Try not setting the settingObject property in the SettingsDetailViewController (and not using it in any method - just comment out those sections). If that makes a difference, it must have to do with SettingsDetailViewController's retain/release of this settingObject
  • Trace the "retainCount" of the settingObject object in SettingsDetailViewController (debugger or NSLog statements) where you use it and after you release it in dealloc. That might give you some clues
pythonquick
The settingObject is set like this:NSManagedObject *settingObject;@property (nonatomic, retain) NSManagedObject *settingObject;If I comment out the setting of SettingObject the problem disappears, so the problem is that.Tracing the retainCount, I can see it's initially set to 5. Curiously, if I click on another tabBar button and come back to the Settings Tab, the error seems to disappear, meaning I can go back to the Summary view and the [cell.descriptionLabel setText..] gives no error. But if I click again a setting and load the Detail view, then the error will occur again.
Marianisho
Is it possible to create a stripped down version of your xcode project, where you can still reproduce the problem? Would be good if you could somehow make that available for download so that I (or fellow SO users) can try it.
pythonquick
+1  A: 

Clang static analysis finds many reference counting errors, so you might want to give it a try.

You can either run it manually, using Run -> Build and Analyze, or you can enable it for all builds via the "Run Static Analyzer" build setting.

Note that this tool presently only supports C and Objective-C, but not C++ / Objective-C++.

oefe