Memory leak — setting variable in init?

2019-07-23 10:46发布

问题:

Memory management has me confused again --

In my .h file, I have:

@property (nonatomic,retain) NSMutableDictionary *properties;

In my .m, I have the following init method, which complains of a leak in Instruments on the self.properties line:

- (id) init {
  self = [super init];

  self.properties = [[NSMutableDictionary alloc] init];

  return self;
}

It also complains of a leak if I don't use the accessor.

Likewise, it leaks if I use this strategy:

NSMutableDictionary *temp = [[NSMutableDictionary alloc] init];

self.properties = temp;

[temp release];

And in dealloc I have:

self.properties = nil;
[properties release];

I thought I was following the rules, but this one is alluding me.

回答1:

If your .h is defined like this:

@interface MDObject : NSObject {
    NSMutableDictionary *properties;
}

@property (nonatomic, retain) NSMutableDictionary *properties;

@end

The following are possible correct implementations of your .m:

@implementation MDObject

- (id)init {
    if ((self = [super init])) {
         properties = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (void)dealloc {
    [properties release];
    [super dealloc];
}

@end

or

@implementation MDObject

- (id)init {
    if ((self = [super init])) {
         self.properties = [NSMutableDictionary dictionary];
    }
    return self;
}

- (void)dealloc {
    self.properties = nil; // while this works,
                           // [properties release] is usually preferred
    [super dealloc];
}

@end

It might be helpful to remember that

self.properties = [NSMutableDictionary dictionary];

is the same as

[self setProperties:[NSMutableDictionary dictionary]];

Those 2 methods that are synthesized for you would look similar to the following:

- (NSMutableDictionary *)properties {
    return properties;
}

- (void)setProperties:(NSMutableDictionary *)aProperties {
    [aProperties retain];
    [properties release];
    properties = aProperties;
}


回答2:

If you have @property(retain) then you shouldn't just alloc and then use the accessor because you've over-retained the object. Either release it after you set the property or autorelease it first.