What's the difference between referring to an instance variable in an objective-c class as this:
self.myIvar
and
myIvar
if it's been declared as a property in the header and synthesized?
What's the difference between referring to an instance variable in an objective-c class as this:
self.myIvar
and
myIvar
if it's been declared as a property in the header and synthesized?
Hello !
If you refer to self.myVar, it will use the @property declared in your header file.
For example
@property(nonatomic, retain) Class *myClass;
If you have
myClass = [ [ Class alloc ] init .... ];
Retain Count will be 1 But if you use
self.myClass = [ [ Class alloc ] init .... ];
Retain Count will be 2 because of the retain property.
It's the same if you set setter || getter method in the @property.
Without the self. part you'll be accessing/assigning the actual data member of the class, without going through the getter/setter generated by @synthesize (or you can write your own getter/setter if you need something more fancy than the default behavior).
Note that in those custom accessors you'd pretty much have to omit the self. part to avoid endless recursion, e.g. if you have a string property called s, a setter could be (this is similar to what is generated when you do @synthesize, by the way):
-(void)setS:(NSString *)newVal
{
if(newVal == s) return;
[s release];
s = [newVal retain]; //if you use self.s here, setS will be called again
}
self.ivar
calls a property method that you can later change or add to, and that might do some memory management as well. For instance, you could make setting self.ivar also change ivar2, increment ivar3, bounds check ivar4, send a message to object5, release object6, play sound7, etc.
ivar
just reads or writes some number of bits in memory.
The difference is that ivar
is just a variable pointing to a location in memory, whereas self.ivar
calls the setter (in the case of self.ivar = x
) and getter (for x = self.ivar
) methods. IE, under the hood, the self.ivar
in these statements gets translated into [self setIvar:value]
and [self getIvar]
respectively . These methods can then handle things like retain/release and any class-specific behaviour on your behalf, and in fact do so by referencing ivar
directly. The @synthesize
keyword automatically generates these getter and setter methods for you to cut down on boilerplate code.
So, ivar
is a location in memory where your object can store something, and self.ivar
wraps class methods around that location in memory to manage access to it. Note that when initializing an object it is usually preferable to set the ivars directly to avoid possible strange behaviour with not-quite-fully-formed objects.
What's the difference between referring to an instance variable in an objective-c class as this:
self.myIvar
and
myIvar
if it's been declared as a property in the header …
Simple: The former does not refer to an instance variable.
It refers to a property named myIvar
. Likewise, the latter refers to an instance variable and not a property.
The property is, of course, misnamed, because a property and an instance variable do not necessarily have anything to do with each other, and indeed a property does not even need to be backed by an instance variable.
Attempting to access self.myIvar
is exactly the same as sending self
a getter message for the property. That is, these two statements:
foo = self.myIvar;
foo = [self myIvar];
are exactly the same.
Likewise, attempting to assign to self.myIvar
is exactly the same as sending self
a setter message. These two statements:
self.myIvar = foo;
[self setMyIvar:foo];
are exactly the same.
By comparison, referring to the instance variable myIvar
(no self.
):
foo = myIvar;
myIvar = foo;
is exactly that: accessing a variable; nothing more.
This means a lot.
The accessors, particularly the setter, tend to have side effects. For example, if the property is declared as retain
, a synthesized setter for it will release the old value of the property and retain the new value. Likewise, if the property is declared as copy
, a synthesized setter will release the old value and make a copy of the new one.
Since an assignment to a property:
self.myProperty = foo;
is an accessor message, that “assignment” will cause the old value to be released and the new value to be retained/copied.
An assignment to a variable:
myIvar = foo;
being nothing more than an assignment to a variable, will not do that. If you owned the old value of myIvar
, you just leaked it, and if you don't already own the new value, you still don't own it, which means it will probably die while you're still holding onto it, leading to a crash later. (See the Memory Management Programming Guide.)
Despite the two looking similar, they are very, very different.
As a general rule, you should use your properties everywhere except init
methods and the dealloc
method, and directly access the instance variables (where you have instance variables) in those methods. (Again, accessors may have side effects; you're likely to not want those side effects in a half-initialized or half-deallocated object.)
… and synthesized?
That doesn't matter. @synthesize
is just one of three ways of telling the compiler how the property's accessors are implemented:
@synthesize
: Compiler, you implement them.@dynamic
: Don't worry about it, compiler; my superclass will dynamically supply the accessors at run time. (Most common in subclasses of NSManagedObject.)- (Foo *) myProperty { … }
/ - (void) setMyProperty:(Foo *) newFoo { … }
: Here are my implementations of the accessors.Failing to do one or more of those things for a property will get you a warning from the compiler and probably some run-time exceptions, because you never actually stated an implementation for the accessors that (by declaring a @property
) you declared the instances would have.