Objective-C memory management and nil? - objective-c

In my book a *joystick that was assigned #property (nonatomic, retain), and it wasn't released only set to nil in the -dealloc method. In the -init method, the same joystick was set to nil. What does this mean?

If you have a property like:
#property (nonatomic, retain)
the setter method generated by synthesize will take care of releasing the object currently pointed to by the ivar before assigning the new one to it. So,
self.property = xxx;
is equivalent (if you like) to:
if (property != xxx) {
[xxx retain];
[property release];
property = xxx;
}
Now, it is considered good practice to set an ivar to nil after releasing it:
[property release];
property = nil;
This is a common release idiom in ObjC.
As you see, if you assign nil to a property (i.e., xxx = nil in the example above) what you get is just this: the ivar will be released and its value set to nil. Assigning nil to a property is therefore just a shorthand for this "release idiom".

Properties are essentially automaticaly generated accessor method to you ivars, you can even override properties, so if you property is call joystick then the automatically generate method is equallent to
- (void)setJoystick:(MyType *)aValue
{
if( aValue != joystick )
{
[joystick release];
joystick = [aValue retain];
}
}
more than this actually happens if you do not have nonatomic, and there maybe stuff to deal with thread access.
Sp you can see that if you set self.joystick you are calling setJoystick: with nil and so release the current value and setting the ivar to nil

Related

Does an object initialize automatically if it is the synthesized property of another object?

When you have one object as a property of another object in Objective-C, does it automatically initialize when you use #synthesize?
does it automatically initialize when you use #synthesize?
Yes, it is initialized to nil (no actual object is allocated, however - this is pointer initialization in the C sense of the word, the init method is not called).
By the way, you don't even have to #synthesize to achieve this behavior - every instance variable, even those which don't have a corresponding #property, are automatically initialized either to nil (in case of objects), NULL (in case of other pointers) or 0 (in case of integers and floating-point numbers) by the Objective-C runtime.
Let's try it:
#interface TypicalObject : NSObject
#property (nonatomic) NSNumber *numberProperty;
#end
#implementation TypicalObject
#synthesize numberProperty;
#end
...
TypicalObject *object = [[TypicalObject alloc] init];
NSLog(#"object.numberProperty = %#", object.numberProperty);
The log statement yields:
object.numberProperty = (null)
So, no, properties do not auto-instantiate. All object instance variables begin as nil, however.
No. The #synthesize does not know how to initialize it. Simple -init?
You can allocate and initialize it in the -init… of the referring object.
You still have to init. Try using lazy initialization:
-(MyPropertyClass*)propertyName {
if(!propertyIvarName) {
_propertyIvarName = [[MyPropertyClass alloc] init];
}
return propertyIvarName;
}
or init the property in viewdidload

incorrect decrement of the reference count of an object that is not owned at this point by caller

Hi everyone i am running my code through the analyzer tool in the IDE where i am getting an indication in the dealloc and saying "incorrect decrement of the reference count of an object that is not owned at this point by caller" i am creating an NSArray and releasing properly my code sample is below
myClass.h
{
NSArray *arrayOfChapters;
}
#property (nonatomic, retain) NSArray *arrayOfChapters;
#end
myClass.m:
-(void)parseAndLoadChaptersAndPages{
self.arrayOfChapters = chapterLoader.arrayOfChapters;
}
-(void)dealloc{
[self.arrayOfChapters release];
[super dealloc];
}
can any one tell me the problem why it is giving me the warning.Thanks in advance.
You can either release the ivar directly ([arrayOfChapters release]), or you can set the property to nil (self.arrayOfChapters = nil) and the setter method will release the ivar for you.
The object owns the ivar arrayOfChapters, but not necessarily the return value of the arrayOfChapters method that you are calling using the property syntax. It's a bit confusing because both the ivar and the method have exactly the same name. In this case the arrayOfChapters method returns the ivar, so it's not a problem. However the analyser thinks the method could theoretically return a different object, in which case you would be over-releasing that object.

Do properties default to nil?

If i don't use an ivar for properties, but do this:
#interface someClass : NSObject
#property (nonatomic, retain) NSArray * someArray;
#end
#implementation someClass
#synthesize someArray = _someArray;
- (void) someMethod
{
if( self.someArray == nil ){
// True on the first call?
}
}
#end
The first time I check self.someArray it returns nil, as does _someArray, but is this guaranteed? I read only that ivars are guaranteed to be nil, and since I don't declare a ivar (_someArray is not an ivar), I am not sure if it will be nil everywhere and every time.
It's always nil. Objective-C initialises all the variables in a class to nil when it is allocated. Synthesised ivars follow the same rules.
Properties are backed by instance variables if they are synthesized automatically -- so yes, by default such properties will return nil.
Yes, all properties, ivars and static variables have always been defined to be initialized to nil. Now with ARC this carries over to __strong stack variables (__strong being the default for all object pointers).

Methods from #synthesize?

When you synthesize a property (see below)
#interface CelestialBody : NSObject {
NSString *name;
}
...
#interface Planet : NSObject {
NSString *name;
int mass;
CelestialBody *moon;
}
#property(nonatomic, retain) NSString *name;
#property(assign) int *mass;
#property(nonatomic, retain) CelestialBody *moon;
...
#implementation Planet
#synthesize name;
#synthesize mass;
#synthesize moon;
...
You get setters and getters for each of the iVars (i.e.)
[newPlanet setName:#"Jupiter"];
[newPlanet setMass:57];
NSString *closestName = [newPlanet name];
int largestMass = [newPlanet mass];
CelestialBody *newMoon = [[CelestialBody alloc] initWithName:#"Callisto"];
[self setMoon:newMoon];
[newMoon release];
but you also get the ability to release the object using ...
// Releases the object (frees memory) and sets the object pointer to nil.
[self setMoon: nil];
There will of course be deallocs for each Class.
// Moon
-(void)dealloc {
[name release];
[super dealloc];
}
// Planet
-(void)dealloc {
[name release];
[moon release];
[super dealloc];
}
Am I getting this right?
gary
Unless your planet object is declared as a property within some other class, using the retain/copy attributes, you can't release it this way.
When you declare a property using retain/copy, the resulting setter will release the old value and assign the new value, retaining or copying it in the process. If you pass nil, you will release the old value and assign nil, retaining or copying it, and retaining/copying nil is nil, so effectively you end up releasing the old value and assigning nil to the ivar.
This is an acceptable way to release instance variables.
In order to be able to release your newPlanet instance this way, you'd have to have declared it in a class as a property with either retain or copy.
As a further example, since your planet object declares its properties in this way, you could release those using this method.
Or in the Planet class's dealloc method, you could do:
self.name = nil;
This would release name and assign nil to it.
"you also get the ability to release the object"
Yes, as long as you didn't declare it with the assign attribute.
As you probably know, one of the reasons (although perhaps not the primary one) for using declared properties is that you can do:
self.moon = aMoon;
rather than;
[self setMoon:aMoon];
They are equivalent. That means that your deallocation can look like this:
self.moon = nil; // Releases and sets to nil
But remember to never just do:
moon = nil; // Sets to nil, doesn't release
It's very good practice to not only release the object, but to set the variable to nil, as you do, because otherwise some other code could mistakenly try to use the pointer that is left in the variable.
Your example shows the synthesis of one class's ivars (those of Planet) but the use of another (whatever "self" is). Is the "newPlanet" property of "self" in your last example also synthesized as (retain)? If so, then: Yes, setting newPlanet to nil will release whatever self's old "newPlanet" was.
I think you are not getting it right.
After your question update, yes, you can do that, and also:
self.moon = [[CelestialBody alloc] initWithName:#"Callisto"];
and release it later, probably in your dealloc method:
self.moon = nil;
Apple Objective-c 2.0 Properties and Memory Management docs are pretty good. Check Mac Dev Center library.

Releasing a property (Objective-C)

I have a #property which is defined like this :
#property (nonatomic, retain) name;
In a function I parse some xml and set the name property.
My question is should I explicitly release previous retained instance before retain a new one ?
For exemple :
myObj.name = [otherObj getName]; // retain count +1
..
myObj.name = [otherObj getName]; // which is a new instance of a name, is the previous name released ?
In a synthesized property setter, the code does something roughly analogous to this (we'll have name be the property name, and _name will be the instance variable to which it refers):
- (void) setName: (NSString *) newValue
{
if ( newValue == _name )
return;
[newValue retain];
[_name release];
_name = newValue;
}
Now, that shows what would happen based on your property declaration above. Depending on the other possible attributes of that property, that function would either use [newValue copy] instead of [newValue retain] (if the 'copy' attribute was specified), or it would all be wrapped in an #synchronized(self) block (if the 'nonatomic' attribute was NOT supplied).
I should also note that since your property refers to an NSString, which implements the NSCopying protocol, you should really be using copy rather than retain, i.e.:
#property (nonatomic, copy) NSString * name;
That will cause the synthesized setter to use -copy instead of -retain, which is safer when you're actually passed an NSMutableString object. An immutable string would ultimately only get retained by the -copy call, while a mutable string would create a new immutable copy. Failing to do that means that the string itself could be changed after it's been passed into the setter, changing the value without your object's knowledge.
If you have synthesized the accessors for your property (with the #synthesize directive), they will take care of releasing the ivar that is backing the property when the property gets reassigned. The only time you might want to explicitly release the ivar is when your object gets deallocated. So, your dealloc method might look like this:
- (void)dealloc {
[name release];
// other cleanup here
[super dealloc];
}