简体   繁体   中英

iPhone - NSMutableArray inside a Custom Object. When to release?

When should I be releasing [self.activeLocations] , which is an NSMutableArray inside my custom object? I am also getting memory leaks in initWithValue .

Also the Location object below. Am I calling this and releasing this properly?

Method in Custom Object.m:

- (id)initWithValue:(NSString *)value {
    if ((self = [super init])) {
        self.couponId = [value valueForKey:@"couponId"];
        self.couponName = [value valueForKeyPath:@"couponName"];
        self.qrCode = [value valueForKeyPath:@"description"];
        self.companyName = [value valueForKeyPath:@"companyName"];
        self.categoryName = [value valueForKeyPath:@"categoryName"];
        self.distance = [value valueForKeyPath:@"distance"];

        NSDictionary *activeLocationsDict = [value valueForKeyPath:@"activeLocations"];
        //self.activeLocations = [[[NSMutableArray alloc] init] autorelease];
        self.activeLocations = [NSMutableArray array];
        for (id val in activeLocationsDict) {
            // Add JSON objects to array.
            Location *l = [[Location alloc] initWithValue:val];
            [self.activeLocations addObject:l];
            [l release];
        }
    }

    return self;
}

- (void)dealloc {
    [super dealloc];
    couponId = nil;
    couponName = nil;
    qrCode = nil;
    companyName = nil;
    categoryName = nil;
    distance = nil;
    activeLocations = nil;
}

My Custom Object.h

@interface Coupon : NSObject {
    NSNumber *couponId;
    NSString *couponName;
    NSString *qrCode;
    NSString *companyName;
    NSString *categoryName;
    NSString *distance;
    NSMutableArray *activeLocations;
}

@property (nonatomic, copy) NSNumber *couponId;
@property (nonatomic, copy) NSString *couponName;
@property (nonatomic, copy) NSString *qrCode;
@property (nonatomic, copy) NSString *companyName;
@property (nonatomic, copy) NSString *categoryName;
@property (nonatomic, copy) NSString *distance;
@property (nonatomic, retain) NSMutableArray *activeLocations;

- (id)initWithValue:(NSString *)value;

This is how I'm using the above initWithValue :

- (NSMutableArray *)createArrayOfCoupons:(NSString *)value {
    NSDictionary *responseJSON = [value JSONValue];

    // Loop through key value pairs in JSON response.
    //NSMutableArray *couponsArray = [[NSMutableArray alloc] init] autorelease];
    NSMutableArray *couponsArray = [NSMutableArray array];

    for (id val in responseJSON) {
        // Add JSON objects to array.
        Coupon *c = [[Coupon alloc] initWithValue:val];
        [couponsArray addObject:c];
        [c release];
    }

    return couponsArray;
}

I get memory leaks on initWithValue in the above method as well...

在此处输入图片说明

Location Custom Object:

- (id)initWithValue:(NSString *)value {
    if ((self = [super init])) {
        self.locationId = [value valueForKeyPath:@"locationId"];
        self.companyName = [value valueForKeyPath:@"companyName"];
        self.street1 = [value valueForKeyPath:@"street1"];
        self.street2 = [value valueForKeyPath:@"street2"];
        self.suburb = [value valueForKeyPath:@"suburb"];
        self.state = [value valueForKeyPath:@"state"];
        self.postcode = [value valueForKeyPath:@"postcode"];
        self.phoneNo = [value valueForKeyPath:@"phoneNo"];
        self.latitude = [value valueForKeyPath:@"latitude"];
        self.longitude = [value valueForKeyPath:@"longitude"];
    }

    return self;
}

- (void)dealloc {
    [super dealloc];
    locationId = nil;
    companyName = nil;
    street1 = nil;
    street2 = nil;
    suburb = nil;
    state = nil;
    postcode = nil;
    phoneNo = nil;
    latitude = nil;
    longitude = nil;
}

First of all, your overridden -init method is completely unnecessary because by default when a method is invoked, the runtime will perform an upward traversal of the inheritance hierarchy until the specified method is found, so it will find NSObject 's -init method and invoke it.

Second, you should invoke release on all of your owned properties (ones with copy or retain ) in your overridden -dealloc method.

Third, in your case, when you call the property setter passing in an object that is already owned locally, you must send the object the release message after invoking the setter to correctly hand off ownership of the object to the receiver.

There are two ways to do this:

One way is to create an object that you own using alloc , copy or new , and then invoke the property setter, passing in that object, then send it the release message.

Another way is to pass in an autoreleased object to the property setter, which will then retain or copy its argument and thereby obtain ownership

- (id)init {
   ....
}

Get rid of this. It does nothing.

- (id)initWithValue:(NSString *)value {
    [super init];

There's a specific pattern you should use for initialization:

- (id)initWithValue:(NSString *)value {
    if (( self = [super init] )) {
      // everything except the return
    }
    return self;
}

Finally, to answer your actual question, assuming you're using retain with your property, there's two places you'll need to release.

Here's the first:

self.activeLocations = [[NSMutableArray alloc] init];

Why : [[NSMutableArray alloc] init] makes your code own the object by retaining it. But the property set also claims ownership by retaining it. You don't really want this NSMutableArray owned by the code and your custom object, you want it owned by your object.

My suggestion is to just use this:

self.activeLocations = [NSMutableArray array];

The second place is in your dealloc:

- (void)dealloc {
    self.activeLocations = nil;

    // ...and everything else you've set as a property using retain

    [super dealloc];
}

(Personally, I've gone back and forth on whether to use dot notation in dealloc rather than [activeLocations release]; . I'm favouring setting to nil using the property now, which puts all the memory management rules in a single location.)

Apple has a great document on memory management you should read: Memory Management Programming Guide: Object Ownership and Disposal .

The answer to when you should be releasing it is a question of whether or not the activeLocations array and all the elements in that array (remember each element in the array is retained by the array itself) are necessary throughout the lifetime of the Location object.

If you use the activeLocations array for some temporary purpose, for example in a method or chain of methods, then don't need it again, or you plan to refresh its members at some later time when you need it next, then it makes sense to release the array (and its elements, which is automatic) when you're done using it, in whatever function last uses the array. You will use the convention

self.activeLocations = nil;

to let the runtime system release the array and set the member to nil.

If, on the other hand, the activeLocations array data is mandatory for the Locations object to function and must exist as long as the Location object exists, then you will want to release the array inside the dealloc method of the Location object, for example:

- (void) dealloc {
    [activeLocations release];

    [super dealloc];
}

As it happens, you're pretty much always going to want to release member objects such as activeLocations in a dealloc method. This ensures that when the Location object is released the members it contains are cleaned up. Remember that Objective-C does not call methods on null pointers, so if you have previously set activeLocations to nil the call in dealloc is a safe no-op.

Given then that you'll always set things up to release in dealloc, now you really just have to ask yourself if you need a release/recreate phase somewhere in your object lifecycle (again, determined by frequency-of-use requirements).

It depends on what you're asking. In the initWithValue: method that you've shared, you are double-retaining the array. It should be released or autoreleased once within initWithValue:.

The array should be released a second time in the custom object's dealloc method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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