views:

113

answers:

2

Hello,

I have a 2 tabs application. In the first one, I'm creating objects of the "Sample" and "SampleList" entities. Each sampleList contains an ID and a set of samples. Each sample contains a date and temperature property.

In the second tab, I'm displaying my data in a tableView. I implemented the

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath

method in order to delete SampleLists. In my xcdatamodel the delete rule for my relationship between SampleList and Sample is Cascade.

My problem is that when I try to delete SampleList I just created, the app crashes and I receive a EXC_BAD_ACCESS signal. If I restart it, then I'm able to delete "old" sampleList without any problems.

Earlier, I had the following problem : I couldn't display the the sampleLists I created since I launched the app, because it crashed too. I received also the EXC_BAD_ACCESS signal. Actually, it seemed that the date of the last sample created of the set was nil. If I am not releasing the NSDate I'm using to set the sample's date, I don't have this problem anymore...

If anyone could help me to find out what could cause my troubles it would be great !!

Here is the method I'm using to create new instances :

SampleList *newSampleList = (SampleList *)[NSEntityDescription insertNewObjectForEntityForName:@"SampleList" inManagedObjectContext:managedObjectContext];
[newSampleList setPatchID:patchID];
NSMutableSet *newSampleSet = [[NSMutableSet alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

for (int i = 0; i < [byteArray count]; i=i+4, sampleCount++) { NSDateComponents *comps = [[NSDateComponents alloc] init]; [comps setYear:year]; [comps setMonth:month]; [comps setDay:day]; [comps setHour:hours]; [comps setMinute:minutes]; NSDate *sampleDate = [gregorian dateFromComponents:comps];

Sample *newSample = (Sample *)[NSEntityDescription insertNewObjectForEntityForName:@"Sample" inManagedObjectContext:managedObjectContext];

[newSample setSampleDate:sampleDate]; [newSample setSampleTemperature:[NSNumber numberWithInt:temperature]];

[newSampleSet addObject:newSample]; [comps release]; //[sampleDate release]; }

[newSampleList setSampleSet:newSampleSet]; // [newSampleSet release];

NSError *error; if (![managedObjectContext save:&error]) { NSLog(@"Could not Save the context !!"); }

[gregorian release];


edit : I found my mistake. I was doing a comparaison for each sampleDate like this:

NSDate *maxDate = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:0];
(...)
for (int i = 0; i < [byteArray count]; i=i+4, sampleCount++) {
    (...)
    if ([maxDate compare:sampleDate] == NSOrdredAscending){
        max = sampleDate;
    }

Where I should have been doing: if ([maxDate compare:sampleDate] == NSOrdredAscending){ [maxDate release]; maxDate = [sampleDate retain]; }

A: 

I like to use a method like the following to get a more informative Core Data error report:

- (void) detailedStoreError:(NSError *)error {
    NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
    NSArray *_detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
    if (_detailedErrors != nil && [_detailedErrors count] > 0) {
        for (NSError *_detailedError in _detailedErrors) {
            NSLog(@" DetailedError: %@", [_detailedError userInfo]);
        }
    }
    else {
        NSLog(@" %@", [error userInfo]);
    }
}

You might use it as follows:

NSError *error;
if (![managedObjectContext save:&error]) {
    [self detailedStoreError:error];
}

A more informative error report may help you with troubleshooting.

Alex Reynolds
Thanks for the advices, but I don't have any error while saving the context. But for now and then I'll do it that way !
Leo
+1  A: 

According to the documentation for NSEntityDescription,

+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context

returns an autoreleased object. So you don't need to release it after:

[newSampleList setSampleSet:newSampleSet];

newSampleList will be autoreleased eventually, which is causing what you see as sometimes getting a EXC_BAD_ACCESS when you restart your app.

Apple's memory management documentation will give you a best practices for when you need to release an object yourself and when objects are autoreleased.

pxl
newSampleSet was created via alloc+init, then retained again by newSampleList, so you will need to do a [newSampleSet release] to balance out the alloc+init. When newSampleList is autoreleased, it will also release newSampleSet.
pxl
I'm doing something wrong about the memory management for sure. I'm taking a look at the documentation you pointed out.I do something wrong with the NSDate. Indeed, I tried to delete everything about dates in my code (and xcdatamodel) and my app is no longer crashing..I'll take a deeper look at these dates and memory management.
Leo
So the memory management documentation link had been useful! Thank you
Leo
No problem! It took me awhile to get the hang of it all as well. The latest versions of xcode also have a handy tool under Build->Build and Analyze. It uses llvm-clang to statically analyze your code and then displays the results in a pretty way. try it out.
pxl