I’m new in iPhone development and after reading Apple documentation and several posts here I still have some doubts about memory management. Please, supouse this basic class:
//MyClass.h
@interface MyClass : NSObject {
NSString *varA;
OtherClass *varB;
NSString *varC;
NSString *varD;
}
@property (nonatomic, copy) NSString *varA;
@property (nonatomic, retain) OtherClass *varB;
@property (nonatomic, copy) NSString *varC;
@property (nonatomic, copy) NSString *varD;
+ (id) initClass:(NSString *)desc;
- (void) method1:(NSString *)desc;
@end
With this implementation:
//MyClass.m
@implementation MyClass
@synthesize varA;
@synthesize varB;
@synthesize varC;
@synthesize varD;
+ (id) initClass:(NSString *)desc{
self = [super init];
if( self ){
self.varA = [NSString stringWithString:desc];
self.varB = [OtherClass initClassWithAutorelease:@"a description"]; //this class return an autoreleased object
[varB aMethod:@"something"];
}
return self;
}
- (void) dealloc{
[varB aMethod:@"something"];
[varA release];
[varB release];
[super dealloc];
}
- (void) method1:(NSString *)aString{
self.varC = aString;
self.varA = [NSString stringWithString:@"new value"];
[varB aMethod:@"something"];
}
@end
At this point what I have in mind is that the instance variables with @property have to be use without self. in the init method of the class and release them without self. in the dealloc, in other methods it is convinient to use self. for all cases. So here are my doubts:
First, I suppose that if I use self.varA= in the init method the retain counter increase so I have to release it in the dealloc method, even if the object has not been created with alloc, copy or new. Or I can use only varA= in the init and I will not need to do a release. For other class methods it’s better to use the setter/getter so I can use self.varA=, ... appendString:self.varA ... or ...=self.varA without problem. Is all this correct?
Second doubt, what is best in terms of memory management and simplicity, to assign to an instance variable an object in the init method with or without autorelease? If I assign to it one without autorelease I will have to dealloc it but if I use autorelease the variable could be released before I want (like the autoreleased self.varB = [OtherClass... that will be used in the dealloc method whenever the MyClass is released).
Third, do I have to dealloc all my instance variables even if I don’t use them in the init method but I could use them (read/write) in other methods of the same class? (Like varC in method1 or varD that is not used).
Fourth, do I need to take care of varA after assigning the new value in method1 if I did it well in the initClass and dealloc methods? In other words, will this generate memory leaks?
Fifth, if I declare with autorelease this class like an instance variable in a ViewController (MyClass *c; … c = [[[MyClass alloc] initClass:@"description"] autorelease];) and I set the @property, do I have to do a release if I use it with c=... instead of self.c=...? As far as I know the behavior is the same than in my example so I should use the setter/get method in the viewDidLoad or viewWillAppear and released it in the dealloc without self..
Sixth and last one, for a instance variable is varA the same that self->varA?
Thanks…
At this point what I have in mind is that the instance variables with @property have to be use without self in the init method of the class and release them without self in the dealloc
This is completely the opposite of what is true. @property just makes the variable public outside of the class. If you have another class call that object, it will look in the header file (.h file), if it doesn’t see a variable by that name, it will throw a warning during compile, and an error during runtime. When using properties with synthesize (btw, your synthesize can be all on one line, doesn’t really matter though, ex: @synthesize varA, varB, varC;), using self automatically retains and keeps a retain count.
in other methods it is convinient to use self for all cases.
Very untrue as well. If anything, this adds another call to the call stack and makes the execution slower (by one operation, but still, one more than needed). Consider this example:
versus
The 2nd one will only access one pointer, where as the first one will have to access 2 pointers to get to the same result.
First, I suppose that if I use self.varA= in the init method the retain counter increase so I have to release it in the dealloc method, even if the object has not been created with alloc, copy or new.
Untrue. The class handles the first retain, and because of this, it handles a release as well. When your class is released, it sends a release to everything it has a retain on. If you do a release in your dealloc, this will actually decrease its retain count to -1 and create a memory error. If you set the property with self.varA = someObject, then it will give it a release when your class is dealloced. If you did self.varA = [someObject retain], then you would have to do a release in the dealloc.
Or I can use only varA= in the init and I will not need to do a release.
Kinda true, you would not need to do a release because you did not do a retain. But if something else lowers the retain count to 0 on this object, there is nothing in your class that forces the object to stay alive, and it will be freed, and if you reference it, memory error.
For other class methods it’s better to use the setter/getter so I can use self.varA=, … appendString:self.varA … or …=self.varA without problem. Is all this correct?
No, see why above. Only use [self setVarA:newValue] if you are changing the instance of the object, the synthesize will handle the rest. Otherwise just use [varA value] to get what ever data you need.
Second doubt, what is best in terms of memory management and simplicity, to assign to an instance variable an object in the init method with or without autorelease? If I assign to it one without autorelease I will have to dealloc it but if I use autorelease the variable could be released before I want (like the autoreleased self.varB = [OtherClass… that will be used in the dealloc method whenever the MyClass is released).
If you are creating a new object in init, autorelease it. You will have to release it in your dealloc if you do just a regular alloc init. The variable will not be released before you want it because of the retain you do on it through the property. EX
This is correct, you do not need to do anything in your dealloc. You are creating an object with a retain count of 2 (one for the alloc you did here, and 1 for the retain you do when the synthesize sets the value in your class). Now, if it autoreleases, its retain will only go down by 1, and you will still have the retain from your property, so it will not release before your class releases
Again, you create an object with a retain count of 2. You will need to do a [varA release] in the dealloc to knock the retain count down enough for it to be released when your class is released.
Third, do I have to dealloc all my instance variables even if I don’t use them in the init method but I could use them (read/write) in other methods of the same class? (Like varC in method1 or varD that is not used).
No, you do not want to send releases to freed objects. You really should never use a dealloc in my opinion, but if you decide you want to for sure, then the worst case is to check to see if the object is null, and if its not, then release it
Fourth, do I need to take care of varA after assigning the new value in method1 if I did it well in the initClass and dealloc methods? In other words, will this generate memory leaks?
No memory leaks from NSString. This method returns an autoreleased object. When you assign a new value to [self varA], it will release the old object, and retain the new object.
Fifth, if I declare with autorelease this class like an instance variable in a ViewController (MyClass *c; … c = [[[MyClass alloc] initClass:@”description”] autorelease];) and I set the @property, do I have to do a release if I use it with c=… instead of self.c=…? As far as I know the behavior is the same than in my example so I should use the setter/get method in the viewDidLoad or viewWillAppear and released it in the dealloc without self..
You don’t need a release in either scenario. The alloc increases the release count by 1, the autorelease will decrease it to 0. If you did self.c, that would increase it to 2, and decrease to 0 (one decrease from autorelease, and one from the property) when your class is released. You do not need to do ANYTHING in dealloc.
Sixth and last one, for a instance variable is varA the same that self->varA?
Yes, they point to the same location in memory.