2

i have a general question about properties and ivars.

ive seen many different examples to use properties and it confuses me a bit.

method 1 only using a property without a corresponding ivar.

@property (...) Type *name;

@synthesize name;

method 2 using a property and an ivar

@interface{
Type *ivarName;
}
@property (...) Type *name;

@synthesize name = ivarName;

method 3 ignoring properties and working with ivars

@interface{
Type *ivarName;
}
ivar = ...;

i currently use method 1 for most things i do, it just works. but i have startet to wonder if i might be missing something here. i have read a lot of questions about ivars VS properties, but none of them seemed to really care about how they work together.

in most sample projects i've seen method 2 is used. so my question is: is there any advantage in defining a property and an ivar, and then assign the property to the ivar, than just having a property?

is the solution as simple as: only with a property can an ivar be set from 'outside'?

i have read: Must every ivar be a property? and Property vs. ivar in times of ARC but was not able to draw a final conclusion.

Community
  • 1
  • 1
Sebastian Flückiger
  • 5,525
  • 8
  • 33
  • 69

4 Answers4

2

When you write:

@synthesize name;

an ivar name is created, and it has the same name as the property. So you can access it with or without self.

In reality if you write

self.name = @"hello";

you are accessing the property, and if you write

name = @"hello";

you are accessing the ivar. Most people (including me) will advise you not to access your ivars directly unless it is really what you want: for example, if you are creating a custom setter or getter for the property. Otherwise always access the property with self.

In my case I always do:

@synthesize name = _name;

The advantage of this approach is that when you forget to write self instead of accessing the ivar you will get an error telling you that the ivar name doesn't exist.

Zalykr
  • 1,524
  • 1
  • 10
  • 20
2

You should never access ivars directly from outside of a class. That's the main function of properties--defining accessor methods for use by other objects. However, it's also good practice to use your accessors from within the same class--this way you can ensure that any appropriate side effects take place (memory management is an obvious example, if you aren't using ARC).

So, Method 3 is usually wrong. Method 1 is roughly equivalent to Method 2--that is, behind the scenes, the runtime is basically creating an ivar for you. Note also that you can set the name of that ivar even if you didn't explicitly define it:

@interface{
//No ivar here!
}
@property (...) Type *name;
@synthesize name = ivarName;
andyvn22
  • 14,696
  • 1
  • 52
  • 74
  • that i didnt know. so when i implicitly give the ivar another name than the property, i will be able to access it with `self.name` and directly with `ivarName` and from the outside i'll of course use `setName` and use the property. – Sebastian Flückiger Mar 24 '12 at 19:23
  • 1
    Yes, although `[self name]` and `self.name` are usually the best options *even from within the same class*. – andyvn22 Mar 24 '12 at 19:27
2

is the solution as simple as: only with a property can an ivar be set from 'outside'?

Essentially, yes. Ivars in Obj-C are (by default) "protected", meaning that the compiler won't allow you to access them externally to the object's own code. For example, given the following class declaration:

@interface Dunstable : NSObject
{
    NSString * crunk;
}
@end

You might think you'd be able to access the ivar after creating the object, but trying results in an error:

Dunstable * d = [[Dunstable alloc] init];
d->crunk = @"Forsooth";    // Error: "Instance variable 'crunk' is protected

That's why ObjC uses accessor methods. Defining them manually was mandatory before the advent of declared properties:

@implementation Dunstable

- (NSString *)crunk {
    return crunk;    // implicit ivar access, i.e. self->crunk
}

- (void)setCrunk: (NSString *)newCrunk {
    [newCrunk retain];
    [crunk release];
    crunk = newCrunk;
}

@end

Now, using the @property and @synthesize directives creates those accessor methods for you (as well as the variable itself). (The manual memory management in the setter is of course also obsolete under ARC.)

It is possible to make an ivar that's accessible from outside the object:

@interface Dunstable : NSObject
{
    @public
    NSNumber * nonce;
}
@end

Dunstable * d = [[Dunstable alloc] init];
d->nonce = [NSNumber numberWithInt:2];    // Works fine

but this isn't considered good Objective-C style.

The Objective-C Programming Language doc contains a "Historical Note" about this:

Note: Historically, the interface required declarations of a class’s instance variables, the data structures that are part of each instance of the class. These were declared in braces after the @interface declaration and before method declarations: [...] Instance variables represent an implementation detail, and should typically not be accessed outside of the class itself. Moreover, you can declare them in the implementation block or synthesize them using declared properties. Typically you should not, therefore, declare instance variables in the public interface and so you should omit the braces.

This is a pretty big change (I was actually surprised that there's no syntax given for ivars declared in @interface anymore in that doc), but it's definitely for the better. You should use declared properties; they do the right thing and make your code cleaner and safer.

jscs
  • 63,694
  • 13
  • 151
  • 195
  • thats truly a great answer! what i wonder now with the arrival of ARC, isnt it a bit 'safer' to use propeties instead of having to retain&release ivars, looking at `[newCrunk retain]; [crunk release];` in your sample? – Sebastian Flückiger Mar 24 '12 at 19:28
  • Yes, that method is completely unecessary (and, with ARC, illegal to write like that) now. That was just an example of the way it was done in the past. – jscs Mar 24 '12 at 19:29
  • allright =) i have grasped it now thanks to all of your answers here. thanks iulius for the clearest and most complete of them and for taking the time to even search for the historical note. its very much appreciated =) – Sebastian Flückiger Mar 24 '12 at 19:38
0

From the second link you supplied, Property vs. ivar in times of ARC, the comment by Denis Mikhaylov on the accepted answer is very telling. He points out that with your case 3, that you can access the iVar through:

classInstance->iVar = @"New value"

But this is considered bad practice. So i'd restate your point as:

Only with a property should an ivar be set from 'outside'

Community
  • 1
  • 1
Peter M
  • 7,309
  • 3
  • 50
  • 91