开发者

Memory management - how best to initialise an instance declared in the header

I've read a few posts on this, but there's still one thing that's not clear for me. I know this might be rather a n00b question, but I've actually got rather far into development without quite grasping this fundamental issue. A symptom of being self taught I guess.

You declare a variable in your header, like so:

@interface SomeClass : NSObject {
    NSMutableArray *anArray;
}

@property (nonatomic, retain) NSMutableArray *anArray;

end

And then in your main file you synthesise it and set it to an initial value:

    @implementation SomeClass

@synthesize anArray

- (SomeClass *)init{
    if (self = [super init]) {
        self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
}
[return self];

And release it when your Class deallocs:

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

Now, when I run instruments, the line

self.anArray = [[NSMutableArray alloc] initWithCapacity:10];

is identified as a memory leak. Is it a memory leak because when you define the variable anArray in the header it allocates memory? (Because I thought it was a null pointer.) Therefore whe开发者_如何学Gon you want to initialise it, and you call [[NSMutableArray alloc] initWithCapacity:10], you are reallocating the memory, and losing the pointer to the original allocation?

So instead, I use the convenience class method:

@implementation SomeClass

    @synthesize anArray

    - (SomeClass *)init{
        if (self = [super init]) {
            self.anArray = [NSMutableArray arrayWithCapacity:10];
    }
    [return self];

This is no longer identified as a memory leak in instruments. And since it's a convenience method, anArray is autoreleased. However, if I am to assume that the instance declaration in the header allocates memory, which would explain the previous issue, then should I still release anArray? Does setting the initial values in this way retain it perhaps?

I understand the difference between

NSMutableArray *anArray = [[NSMutableArray alloc] initWithCapacity:10];

and

NSMutableArray *anArray = [NSMutableArray arrayWithCapactiy:10];

but what I'm not sure I understand is when you've declared NSMutableArray *anArray in your header, which of the two approaches you should use and why. And whether or not if you use the second approach, you should still release anArray when you call dealloc.

I might add that I've found the following posts/links useful:

  • Suggest the best way of initialization of array ( or other objects )
  • What is the cost of using autorelease in Cocoa?
  • http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
  • What is the difference between class and instance methods?


alloc'ing an object starts it off with a reference count of 1. Setting a property that has the 'retain' attribute also increases the reference count.

So, that means this is usually bad:

@property (nonatomic, retain) Object * variable;

...

self.variable = [[Object alloc] init];

Because variable now has a reference count of 2.

When setting a object's member variable, just do this:

variable = [[Object alloc] init];

You should also realize that this works

        self.anArray = [NSMutableArray arrayWithCapacity:10];

Because "arrayWithCapacity" (and other similar factor methods) autoreleases the object it returns, so after you set the property, it essentially has a reference count of 1.


It's not the instance that allocates the memory. You're right to assume that in Objective-C (at least on all Apple-based operating systems), newly initialized classes have all their ivars set to 0 (or nil or NULL as appropriate).

The problem you're seeing is that you're using the property, not the ivar in your initialization. Since you declared your property as retain, using the property accessor to set it automatically retains it.

So, when you initialize you either have to take ownership and set the ivar directly, or do like you're doing and use the property accessor to set the property and then relinquish ownership in the init method (by either releasing an object you own or, as you did in your second instance, using the convenience constructor so that you never owned the returned instance).

So just remember, if you ever use the property accessors, even within the class itself, you will get the features you set on the property (e.g., nonatomic, retain, etc.). You use the property accessors whenever you do one of the following:

// in these cases the property takes ownership through the
// retain keyword, so you must not take ownership yourself
self.anArray = something;
[self setAnArray:something];
[self setValue:something forKey:@"anArray"];

You would access your ivar directly like:

anArray = something; // in this case you must take ownership
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜