The Leaks instrument tells me that I have a memory leak when I use decodeObjectForKey within initWithCoder. For example:
Class.h
{
MyObject *myObject;
}
#property (nonatomic, retain) MyObject *myObject;
Class.m
#synthesize myObject
-(void)dealloc{
[myObject release];
[super release];
}
-(id)initWithCoder:(NSCoder *)decoder{
if (self = [super init]{
self.myObject = [decoder decodeObjectForKey:#"MyObject"];
}
return self;
}
Per request in the comments:
-(void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject:myObject forKey:#"MyObject"];
}
Leaks reports a leak of type NSCFString on the line;
self.myObject = [decoder decodeObjectForKey:#"MyObject];
As I understand it, decodeObjectForKey returns an autoreleased object. Since I immediately assign that value to the myObject property, which is specified as (nontoxic, retain) in the property definition, I retain the autoreleased object through the setter method of the myObject property. The myObject is then released in the dealloc method. I don't understand where the leak is if I understand the sequence correctly. Also why is it reported as a NSCFString when the type is MYObject?
Any thoughts would be appreciated, including if my assumptions above are correct.
Look carefully at your -dealloc method. You are calling [super release]; when you should be calling [super dealloc];.
Calling [super release] in this case is the same thing as calling [self release], since you're not overriding the -release method. If your -dealloc method is called, your object has already been fully released, so this is unnecessary. Since you are overriding the -dealloc method, you must call [super dealloc] to also free any memory allocated by the superclass.
You can refer to the NSObject documentation to see how to override dealloc correctly.
Related
Let say i have an class named as MyTestClass.h.
Class structure is look like
#interface MyTestClass : NSObject {
NSString *testString;
}
#property (nonatomic, retain)NSString * testString;
#end
.m file
#implementation MyTestClass
#synthesize testString;
-(id) init{
[self setTestString:#""];
return self;
}
-(void)dealloc{
[self.testString release];
testString = nil;
[super dealloc];
}
#end
Now i created an object of MyTestClass and assigned testString twice
MyTestClass * myTestClass = [[MyTestClass alloc] init];
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
Now i think, two times my testStrings memory is leaked!! (one through init() and another one through my first setTestString method)
Am i correct? or will #property (nonatomic, retain) handle/release previous allocated memory?
or ,in this kind of cases ,will i need to override the setTestString() in MyTestClass.m like below code
-(void)setTestString:(NSString *)tempString{
[testString release];
testString = nil;
testString = [tempString retain];
}
Any help on this question is appreciated.
Thanks.
Any help on this question is appreciated.
I'll take this as a licence to make sone observations not necessarily directly related to your question.
Firstly, if you declare a retain property (as you have done) and synthesize it, the automatically generated getters and setters handle memory management correctly for you.
If you manually create setter (which you are allowed to do even with an #synthesize existing), you have to do the memory management yourself. Use either of trojanfoe's examples.
The setter in your question contains a bug in that if testString == tempString i.e. you assign the value of the property to itself, you could end up with assigning a dangling pointer to the property because you effectively release tempString and then retain it.
This is an implementation detail that you an safely ignore, but string literals e.g. #"blah" are compiled into the executable and will never be deallocated no matter how many times they are released. So, with your example, even if the setter did not do correct memory management, there will be no leak.
By the way, the normal pattern for an init method is
-(id) init
{
self = [super init];
if (self != nil)
{
// init stuff
}
return self;
}
or logical equivalent.
You should get into the habit of using it because you need to call the super class's init method and it is allowed to change the value of self, even to nil.
Also, while it is very good practice normally to set the object reference to nil after releasing it, in both cases when you do it, it is unnecessary. the first time, the variable is about to go out of scope and the second time you immediately assign it from some other object.
It's not a leak. Synthesized variable are correctly handled.
A synthesized method is implemented in this way (for a retain keyword)
#property (nonatomic, retain) NSString *string;
//backed by variable NSString *_string;
- (void)setString:(NSString*)newString
{
if (newString != _string) {
[_string release];
_string = [newString retain];
}
}
Of course this is a leak:
- (void)aMethod //of my class with string property
{
NSString *aString = [[NSString alloc] initWithString:#"hello"];
self.string = aString; //retain count of 2
self.string = #"hello2"; //retain count of 1 for aString
//now I don't release aString.... leak
}
If you use the auto-generated setter (in your case, setTestString:, which is also called by self.testString = ...;), the previous value of a retain property is released before being set. So no, there is no leak in the code you posted above.
The synthesized setter method should do the right thing. Here's an example of it's implementation:
- (void)setTestString:(NSString *)tempString
{
[tempString retain];
[testString release];
testString = tempString;
}
or:
- (void)setTestString:(NSString *)tempString
{
if (tempString != testString)
{
[testString release];
[tempString retain];
testString = tempString;
}
}
the dealloc is only called when the instance is destructed.
if you do :
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
in the same block, you're juste calling twice the setter. there is no memory leak.
When you use #synthesize on a property that specifies retain, the setter that's generated will handle the retain/release correctly for multiple assignments. As long as you use self. rather than going directly to the backing variable and do a final release in dealloc you should be fine.
#interface foo: NSObject
#property (nonatomic, retain) NSMutableArray *aMutableArray;
#end
#implementation
#synthesize aMutableArray
-(void)somefunction {
// Illustration
self.aMutableArray = [[[NSMutableArray alloc]init]autorelease];
self.aMutableArray = [[[NSMutableArray alloc]init]autorelease];
self.aMutableArray = [[[NSMutableArray alloc]init]autorelease];
}
#end
I have done code similar code to this in other parts of my program, but I needed to be certain that this does not cause a memory leak. With my understanding of autorelease, this object is released correctly right?
[EDIT - added question]
One question though: the property above has a retain attribute, so when the compiler creates the setter function, the setter code will look something like this:
somecode..
retain newObj
release oldObj
somecode..
in the code above, I assigned 3 objects to aMutableArray.
Each time they are assigned, the setter function did a retain on the newObj and a release on the oldObj. So, since the setter method already did a release, will there be a problem when the autorelease kicks-in to release the object a second time?
Yes, it will be released correctly if you also release it dealloc method:
- (void) dealloc{
[aMutableArray release];
[super dealloc];
}
Note also that you can shorten your code using equivalent convenience +array method of NSMutableArray:
self.aMutableArray = [NSMutableArray array];
1- Is these anything wrong with the way
i am deallocing the object?
2- Does my dealloc override the dealloc
for NSManagedObject?
3- Do i need to dealloc super even
though my object is an
NSManagedObject type and core data ia
responsible for it?
#interface MyClass : NSManagedObject
#property (nonatomic, retain) NSString *coreDataString;
#property (nonatomic, retain) NSNumber *coreDataNumber;
#property (nonatomic, retain) CoolObject *coolObject;
#end
.
#implementation MyClass
#dynamic coreDataString;
#dynamic coreDataNumber;
#synthesize coolObject;
- (void)dealloc
{
[self.coolObject release];
}
#end
Yes, you are not calling [super dealloc].
Yes.
Yes, you must always call [super dealloc] at the end of your dealloc method. Otherwise memory will not be freed correctly.
You should call release on the member variable directly instead of using the property. You also should still call the super dealloc. So your dealloc would look like this:
- (void)dealloc
{
[coolObject release];
coolObject = nil;
[super dealloc];
}
Otherwise, you can set the property to nil which will automatically release the local variable if necessary. The above way is preferred so you don't accidentally run a complicated function that could be overriding the property's setter.
You should always call [super dealloc] in the dealloc method. But in subclasses of NSManagedObject you should never use the dealloc method at all. use - (void)didTurnIntoFault instead.
You are overriding the parents - (void)dealloc method. When you override a parent object's method, the parent's method is never called until you explicitly call the super's method. In your case, the parent's - (void)dealloc is not called. To fix this, you must call [super dealloc] to ensure that the parent's instance variables are deallocated too.
Why doesn't this common property initialization scheme risk failure when the synthesized setter tries to release the undefined myArray object? Or are property objects automatically initialized to nil and I don't need to be doing this at all?
#interface myClass : NSObject {
NSArray* myArray;
}
#property (nonatomic, retain) NSArray* myArray;
#end
#implementation myClass
#synthesize myArray;
-(id)init {
if ( self = [super init] ) {
self.myArray = nil;
}
return self;
}
...
Object instance variables in Objective-C are initialized to nil by default. Furthermore, messaging nil is allowed (unlike calling a method on null in function-calling languages like Java, C# or C++). The result of a message to nil is nil, this calling [nil release]; is just nil, not an exception.
On a side note, it's best practice to assign/call instance variables directly in -init and -dealloc methods:
-(id)init {
if ( self = [super init] ) {
myArray = nil;
}
return self;
}
- (void)dealloc {
[myArray release];
[super dealloc];
}
As others have stated, the instance variable is already initialised to nil.
Additionally, as per Apple's documentation, instance variables should be set directly in an init method, as the getter/setter methods of a class (or subclass thereof) may rely on a fully initialised instance.
It's already initialized to nil.
I have a simple question, that in a class I have a variable with property retain
//Classs ArrayClass has this array
#property(nonatomic, retain) NSMutableArray *array;
Now when I do
self.array = [SomeClass getArray];
I need to release the array...
Now If I have object of ArrayClass and when I do
arrayClassObj.array = [SomeClass getArray];
So in this case, Is the setter method is called? Do I need to release in this case.
The setter generated by #synthesize will (since you told it to retain) handle the retaining and releasing for you. If you override it, it's on you.
In your dealloc, don't forget to release it as well -- safe, don't forget, because messages to nil are not errors (and you should be setting a var to nil if you're through with it).
In both cases the object being assigned it's array property from [SomeClass getArray] will need to release it itself, unless you set the property to nil.
The following is required by the class owning the array property.
// ArrayClassObject dealloc (self in first example)
-(void)dealloc
{
[array release];
[super dealloc];
}
When you assign the property then assign it nil, the [array release] is still required in the dealloc method, but since you're assigning nil to it, it won't have any effect.
// someArrayObj must have [array release] in its dealloc method
someArrayObj.array = [SomeClass getArray];
// But you can do it manually by assigning nil
someArrayObj.array = nil;