Question

Looks like I did not understand memory management in Objective C... sigh.

I have the following code (note that in my case, placemark.thoroughfare and placemark.subThoroughfare are both filled with valid data, thus both if-conditions will be TRUE

item is tied to a ManagedObjectContext. The managed variables in item such as place have setters/getters created with @dynamic. Thus, the declaration is

@property (nonatomic, retain) NSString *place;
@dynamic place;

Later in the code, in the ReverseGeocoderDelegate, I access it:

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {

if (placemark.thoroughfare) {
    [item.place release];
    item.place = [NSString stringWithFormat:@"%@ ", placemark.thoroughfare];        
} else {
    [item.place release];
    item.place = @"Unknown Place";
}
if (placemark.thoroughfare && placemark.subThoroughfare) {
// *** problem is here ***
    [item.place release];
    item.place = [NSString stringWithFormat:@"%@ %@", placemark.thoroughfare , placemark.subThoroughfare];
}

If I do not release item.place at the marked location in the code, Instruments finds a memory leak there. If I do, the program crashes as soon as I try to access item.place outside the offending method.

Any ideas?

Was it helpful?

Solution

First of all, I would change the logic like this:

NSString *newPlace = nil;

if (placemark.thoroughfare && placemark.subThoroughfare) {
    newPlace = [NSString stringWithFormat:@"%@ %@", placemark.thoroughfare , placemark.subThoroughfare];
}
else {
    if (placemark.thoroughfare) {
        newPlace = [NSString stringWithFormat:@"%@ ", placemark.thoroughfare];
    }
    else {
        newPlace = @"Unknown Place";
    }
}

item.place = newPlace;    // Either nil of valid string can be assigned to

Using release for simply re-initializing pointer is not so recommended by many. You don't have to do this if it was to save some memory.

Your previous logic does releasing twice. What release does initially is simply decrementing retainCount. If it's 0, then the object is deallocated. Object will not be deallocated until its retainCount is 0.

Assuming your item has the property retain and since stringWithFormat: returns autoreleased string, so at the 2nd release, you were trying to release what was going to be autoreleased anyway.

Best way to clearing an object multiple times is simply assigning nil to it.

OTHER TIPS

A starting point would be to re-read about properties because you don't need to do `[item.place release]' anywhere. So you can remove them. The dynamic code created by the runtime to enable that property automatically handles releasing anything previously assigned to it.

Also, the [NSString stringWithFormat:... creates an autorelease object (not sure if you knew that :-) which means that if you where manually managing the memory for a variable (not a property) then you would have to retain/release it. But because you are using properties, you don't.

I cannot see why instruments is finding a memory leak. Perhaps some code higher up is to do with it. For example if you went item.place = [NSString alloc] initWith...]; then I think you would need it.

The crash I would suspect to be because of the releases causing retain counts to be zero and triggering exec bad access errors.

Hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top