So ... I'm still fairly new to Objective C ... taking some iTunes U corses ... doing some exercises and all ...
But when you uses to do @synthesize myProperty = _myIvarPropertyNameToUse; ... iOS 5 would create an ivar that would "back" the property.
What exactly is going on here as far as where things sit in memory ...
(1) Is the ivar a true variable? ... or is it a pointer to the location of the property in the object?
(2) The property is on the heap, (being part of the object), right? Is the ivar on the heap as well?
I think I may be losing the big picture ... what's the point of having a property backed by an ivar?
thanks,
An Objective-C object is just a C struct that is allocated on the heap (well, more or less). When you declare an instance variable (ivar), it is defined as an offset into that struct. So if you manually declared some ivars like this (don't do it this way anymore, but it illustrates the point):
@interface Foo : NSObject {
NSString *ivar1;
NSString *ivar2;
}
Then when you +alloc
a new instance (call it foo
), the struct will be some header followed by the ivars of NSObject followed by memory for ivar1
followed by memory for ivar2
. ivar1
will be the foo
point plus some offset. (This isn't exactly true anymore, but stay with me; it's simpler to understand the old implementation.)
Since foo
is a pointer to a struct, you can actually refer directly to this offset pointer as foo->ivar1
. It really is a struct. Never do this, but it is legal syntax.
Inside of the @implementation
block, ivar1
is automatically translated to self->ivar1
. Don't worry too much about how self
is implemented, but trust that it's a pointer to your struct. Again, never use this ->
syntax. It's an underlying implementation detail (and isn't always possible anymore; see below).
OK, so that's what an ivar is. In the old days (ObjC 1.0), that's actually all we had. You declared your ivars, and then you hand-created accessor methods that would set and return their values.
Then ObjC2 comes along, which in some cases also gave us something called the non-fragile ABI. That changes the underlying implementation of ivars somewhat, so you can't always actually use ->
anymore. But you shouldn't have been using it anyway. Even so, it's simpler to pretend things are the old way. More to the point, ObjC2 added this new thing called "properties." A property is just a promise to implement certain methods. So when you say:
@property (nonatomic, readwrite, strong) NSString *property;
this is almost identical to saying the following:
- (NSString *)property;
- (void)setProperty:(NSString *)aProperty;
(The difference is very seldom important.) Note that this doesn't provide an implementation. It doesn't create ivars. It just declares some methods.
Now in ObjC1, we wrote the same accessor code over and over and over again. You had 20 writable ivars, you wrote 40 accessor methods. And they were almost identical. Lots of opportunities to mess up. And a lot of tedium. Thank goodness for Accessorizer.
With ObjC2, the compiler would give you the most common implementation for free if you added @synthesize
. It would automatically make an ivar with the same name as the property, and write a getter and (if needed) setter to read and write that ivar. Passing =_property
just changes the name of the ivar used. We call this the "backing ivar."
Now, in the latest version of the compiler, you don't even need @synthesize
. This pattern is so insanely common, and has been for decades, that it is now the default unless you tell the compiler not to do it. And it automatically synthesizes an ivar with a leading underscore (which is best practice).
The one other piece of information you should know is that you should always use the accessor to access the ivar, even inside of the object. The only exceptions are in the init
and dealloc
methods. There you should directly access the ivar (using the leading underscore).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With