What is the difference between ivars and properties in Objective-C

ennuikiller picture ennuikiller · Nov 13, 2010 · Viewed 20.2k times · Source

What is the semantic difference between these 3 ways of using ivars and properties in Objective-C?

1.

@class MyOtherObject; 
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;

2.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
@property (nonatomic, retain) MyOtherObject *otherObj;

3.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}

Answer

willc2 picture willc2 · Nov 13, 2010

Number 1 differs from the other two by forward declaring the MyOtherObject class to minimize the amount of code seen by the compiler and linker and also potentially avoid circular references. If you do it this way remember to put the #import into the .m file.

By declaring an @property, (and matching @synthesize in the .m) file, you auto-generate accessor methods with the memory semantics handled how you specify. The rule of thumb for most objects is Retain, but NSStrings, for instance should use Copy. Whereas Singletons and Delegates should usually use Assign. Hand-writing accessors is tedious and error-prone so this saves a lot of typing and dumb bugs.

Also, declaring a synthesized property lets you call an accessor method using dot notation like this:

self.otherObj = someOtherNewObject; // set it  
MyOtherObject *thingee = self.otherObj; // get it 

Instead of the normal, message-passing way:

[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it 

Behind the scenes you're really calling a method that looks like this:

- (void) setOtherObj:(MyOtherObject *)anOtherObject {

    if (otherObject == anOtherObject) {
        return;  
    }

    MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
    otherObject = [anOtherObject retain]; // put the new value in  
    [oldOtherObject release]; // let go of the old object
} // set it

…or this

- (MyOtherObject *) otherObject {  
    return otherObject;
} // get it

Total pain in the butt, right. Now do that for every ivar in the class. If you don't do it exactly right, you get a memory leak. Best to just let the compiler do the work.

I see that Number 1 doesn't have an ivar. Assuming that's not a typo, it's fine because the @property / @synthesize directives will declare an ivar for you as well, behind the scenes. I believe this is new for Mac OS X - Snow Leopard and iOS4.

Number 3 does not have those accessors generated so you have to write them yourself. If you want your accessor methods to have side effects, you do your standard memory management dance, as shown above, then do whatever side work you need to, inside the accessor method. If you synthesize a property as well as write your own, then your version has priority.

Did I cover everything?