问题
In my last question (here), I had an issue where I was getting an EXC_BAD_ACCESS because I was releasing the variable I had just allocated:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
should have been
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
However, stack is a retained property of my class. It's declared like so:
@interface StateStack ()
@property (nonatomic, retain) NSMutableArray* stack;
@end
I was under the impression that when you assign a 'retain' variable, it automatically increments the retainCount of the object. So you are supposed to start by releasing your pointer (as here).
Why are these two cases different? Thanks!
回答1:
There is no such thing as a "retain variable". It's a retain property — meaning the setter method behind the property retains the new value and releases the old one. But assigning to a variable just assigns. In fact, the reason people generally recommend assigning directly to the instance variable in init
is specifically so that it doesn't go through the setter, because the setter could conceivably have side effects you don't want in init
(when your object isn't fully constructed yet).
Note: I'm talking about normal memory-management rules here. This is all different if you're using ARC. But I assume you would have mentioned if you were.
回答2:
Because you had to assign the property, not the instance variable. When you assign to the property it's going to retain the variable again and then you're not going to have the issue. Here's how your code should have been:
NSMutableArray* s = [[NSMutableArray alloc] init];
self.stack = s;
[s release];
This way you're not assigning to the variable, but using the property (that's, in fact, a method). If you did not release in this case then you'd have a memory leak in your code.
When you did stack = s you assigned directly to the instance variable and the array was never retained.
回答3:
self.stack
and stack
are two completely different things. When you use stack
, you are accessing an instance variable, not a property. This means that your accessor methods aren't called, which means automatic memory management isn't used. This is why you shouldn't release s
in your example.
If you used self.stack
instead, then you would be using a property. The compiler will treat self.stack = value
exactly the same as [self setStack:value]
, and self.stack
the same as [self stack]
. Since accessors are being used, memory management will be taken care of to match the way you defined your property, and you should release a value after assigning it.
回答4:
Maurício has the right answer: be sure to assign to the property to gain the benefits of @property. To clarify the point somewhat, try using code like this:
@interface StateStack : NSObject {
NSArray *_stack;
}
@property (nonatomic,retain) NSMutableArray *stack;
@end
@implementation StateStack
@synthesize stack=_stack;
@end
Now, if you try:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
You'll get an error, which will mean you tried to set the ivar rather than the property as intended. This mismatch between ivar name and property name is against Apple's recommendations, but it's a fine way to help you develop the habit of using property assignment when you intend to do so.
来源:https://stackoverflow.com/questions/6823411/clarification-on-when-to-release-pointers-after-allocating