6

Working on iPhone, after a lot of headache and memory problems I just realized from other examples that we do not need to necessarly create @properties for each instance variable we define in header file. And actually I found out ivars easy to just allocate and release it after I use anywhere in the class, for @properties I have to use autorealese or I have serious problems and becareful how I allocate..

For instance for objects below, @properties(retain/copy..) is not used in headers in many examples;

{
NSURLConnection *connection;
NSMutableData *xmlData;
NsMutableString *string
} 

But for some strings or object types @properties is used, I know that when we set @property cocoa creates some setters getters which are handling the relasing and retaining of the objects. But seems like as for xmlData or connection instance variables we do not need that and they do their job like this.

Are there some reference guidelines I can keep in mind on deciding whether or not to create @property's or just use simple ivars?

My only problem when using properties is not becuase I am lazy to define it, but when I carefully allocate and init them in code, I have to use autorelase and dont feel like I have the control when to release reset and allocate it again, and it gives me one more thing to worry about while and when and how should I release, reset it. I find ivars I can alloc and release anytime once anywhere easily without worrying about anything..or I am missing other things here.

Tnx

Spring
  • 11,333
  • 29
  • 116
  • 185

4 Answers4

6

There seem to still be some misconceptions flying around about properties.

that we do not need to necessarly create @properties for each instance variable we define in header file

Correct. You can use private instance variables directly in your implementation file. However, since synthesized properties come with free memory management, you might as well take advantage. My rule of thumb is to use the ivar directly until the first time I find myself writing:

[ivar release];
ivar = [newIvar retain];

As Sam says, there is already a potential bug there if iVar == newIVar. This is the point at which I switch from using ivars directly to creating a property. However, I put the declaration of the new property in a class extension in the implementation file. This means that the property is officially not part of the public interface (and will cause compiler warnings if used accidentally).

when we set @property cocoa creates some setters getters which are handling the relasing and retaining of the objects.

Actually, no. The @property just declares a property. In order to automatically generate the getter and setter, you need to @synthesize it. You could, alternatively write your own getters and setter which do not even have to reference a real ivar.

Technically, you should not use the property in the init or dealloc methods because a subclass might have overridden them or (in dealloc) you might set off a KVO notification.


From Sam's answer and comments

If you want a property regardless, you could use a private interface at the top of the implementation file

As I say above, private categories have sort of been obsoleted by class extensions (which is near enough the same thing but allows you to put the implementation of the methods in the main class implementation).

If you want the benefits of using dot notation shorthand

Some of us would argue that there are no benefits to dot notation. It's a gratuitous and needless pollution of the struct member syntax. However, dot notation has no relation to @property declarations. You can use dot notation for any accessors no matter how they were declared, provided they adhere to the pattern -foo and and -setFoo:

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • Hmm I think your explanation about '@property' and '@synthesize' is not fully correct. '@property' is indeed a way to tell the compiler to generate accessors for a property (ivar) and there is no need for '@synthesize' to generate the accessors. '@synthesize' is used to generate the ivar so that the accessor 'methods' generated by '@property' can access them. Alternatively you could define the ivars by yourself in the header file . So there is no '@synthesize' but there are of course the getters and setters declared by '@property'!!! – Alexander Nov 13 '12 at 12:35
  • @Alexander No. `@synthesize` is (or was when I wrote the answer) necessary to auto generate the accessors. It would also generate the ivar if you hadn't already done it. This has changed in recent releases of clang so that `@synthesize` is assumed to be there if you leave it out. – JeremyP Nov 14 '12 at 13:27
4

Create properties only for variables that need to be accessed from outside the class. Any class variables that are used internally need not have getters/setters defined.

Generally speaking an abundance of properties indicates high coupling and poor encapsulation. You should restrict what variables your class exposes in the interface.

EDITED to respond to comment:

Using properties over direct access may be preferred because it gives you easy memory management.. for example:

// interface
@property (retain) Object *someVar;     

// implementation
self.someVar = otherVar;

is the same as

// implementation
if (_someVar != othervar)
{
    [_someVar release]
    _someVar = [otherVar retain];
}

However you should not needlessly expose vars in your interface because it opens the class up for people to use in the wrong way.

If you want a property regardless, you could use a private interface at the top of the implementation file

@interface TheClass(Private)
    // private stuff
@end
Sam
  • 3,659
  • 3
  • 36
  • 49
  • the link in the comment above says :"Properties are just setters and getters for ivars and should (almost) always be used instead of direct access." why is that? – Spring Aug 04 '11 at 13:47
  • 1
    That is right... just to complement, when you use @property and do not declare the ivars, the instance variable is created on runtime. so, it is as if you had it declared. – Marsson Aug 04 '11 at 14:03
  • @Sam tnx that relasing the object before retaining another obj makes me confused..if I dont create property and handle manually, doesn't it crash if there is nothing to release? – Spring Aug 04 '11 at 14:07
  • 2
    You seem to be saying two different things: first you say only to use properties for public access; then in the edited section you say properties are preferred b/c of the memory management aspects. I agree with your revised take on the matter, but the conflict between the two sections is bound to cause confusion. – Caleb Aug 04 '11 at 14:13
  • @Caleb should I still take reference "if I dont need to access from outside it is ivar" else property? or access with property cause it manages memory well? – Spring Aug 04 '11 at 14:20
  • 2
    Actually just `[_someVar release]; _someVar = [otherVar retain];` is not safe. Since `_someVar` and `otherVar` could reference the same instance. Its better to be safe and do `if (_someVar != otherVar){ [_someVar release]; _someVar = [otherVar retain]; }`. – PeyloW Aug 04 '11 at 14:23
  • I'm saying don't use properties if it is a private class variable. If you want the benefits of using dot notation shorthand, DO use a property but put it in a PRIVATE interface at the top of the implementation file. From very personal experience, I have worked with programmers that create a PUBLIC INTERFACE property for EVERYTHING and it causes an absolute nightmare for maintenance because everybody starts modifying variables from every other class in the code. If you want more info on this, Google "Why Getters and Setters are Evil" – Sam Aug 04 '11 at 14:23
  • @XDeveloper - it won't crash if the object is nil. It will crash if you have released elsewhere but generally you will only be releasing without reassigning from the dealloc- otherwise you will have to remember to nil the pointer – Sam Aug 04 '11 at 14:35
  • 1
    @Sam: You do not need to have properties to use dot notation. You only need a getter and setter. – JeremyP Aug 04 '11 at 14:46
  • @Sam my problem is when use properties, then when I allocate it in code, I have to use autorealese and dont feel I have the control when to release and allocate it again, ivars I can release anytime once I allocate it anywhere easily without worrying about anything..? – Spring Aug 04 '11 at 14:52
  • 1
    Hmmm... I'd say that properties provide the best encapsulation one can have: no direct access to internals. I don't see the link between strong coupling and properties either. On the contrary. – Rudy Velthuis Aug 04 '11 at 15:37
  • I always properties. For private class data, they go into the private class extension. I think code that does this is just generally a better citizen and is easier to work with and less error prone. – occulus Apr 02 '13 at 09:20
1

It has long been custom to access ivars directly. That is, IMO, fine from inside the same class, although many properties are classes and then properties provide protection against retain/release issues.

IMO, it is, however, preferrable to encapsulate most ivars into properties, especially those that have retain/release semantics, but also those that need special handling, i.e. for which you write your own handlers, instead of using the synthesized ones. That way you can filter access to certain ivars, or even create properties that don't have any backing storage, and are just "aliases" to other properties, e.g. an Angle class that has a degrees property giving the angle in degrees, and a radians property denoting the same angle in radians (this is a simple conversion), or a property that must do a dictionary search to find its value, etc.

In Delphi, which was (AFAICT) one of the first languages with properties as language construct at all, it is customary to wrap ALL ivars in properties (but not all have to be public), and there are many such "unreal" (I am deliberately avoiding the term "virtual" here) properties, i.e. the ones that are only implemented in code, and not just getters and setters for an ivar.

Properties provide encapsulation, abstraction and a degree of protection against certain often made errors, and that is why they are to be preferred over direct access to ivars, IMO.

Addition

It doesn't make sense to declare and implement (either via @synthesize or with custom setters and getters) public properties for each ivar. Only expose publicly what others may need. Internal state can also be exposed to your own code via properties, but that should be done with a private or empty category in the implementation file. That way you get the automatic handling of retain/release and still don't expose them to the public.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • my problem is when use properties, then when I allocate it in code, I have to use autorealese and dont feel I have the control when to release and allocate it again, ivars I can release anytime once I allocate it anywhere easily without worrying about anything..? – Spring Aug 04 '11 at 14:52
  • Hearing what I heard about ARC, you'll "lose" much more "control". You don't have to use autorelease when using properties. The following will do too: `a = [[AClass alloc] init]; myInst.myproperty = a; [a release];`, and no autorelease required. – Rudy Velthuis Aug 04 '11 at 15:06
  • if a here is a property retain/copy can I release that object like that whenever I want? I read I cant..also I had a lot of memory problems by making all properties autorelease? – Spring Aug 04 '11 at 15:38
  • You only release what you retain/copy/alloc. If you pass something to a property of another class, or your own class, the property will (have to) take care of its memory management, and you don't have to worry about it. You must, of course, release items you retained in your own class, in your `dealloc`. – Rudy Velthuis Aug 04 '11 at 15:45
1

First of all, let me say that Sam's answer is complete, IMO, and gives you clear guidelines (+1 from me).

My only problem when using properties is not becuase I am lazy to define it, but when I carefully allocate and init them in code, I have to use autorelase and dont feel like I have the control when to release reset and allocate it again, and it gives me one more thing to worry about while and when and how should I release, reset it. I find ivars I can alloc and release anytime once anywhere easily without worrying about anything..or I am missing other things here.

You should not worry about autorelease in the following idiom:

self.stringProperty = [[[NSString alloc] initWith...] autorelease];

because this is the way that things are meant to work;

EDIT: [the above statement has several parts:

  1. the object is allocated and initialized (retain count is 1);

  2. immediately, the allocated object is also autoreleased; this means that the object will be released automatically, (more or less) when the control flow gets back to the main loop;

  3. in the very same statement, the allocated object is assigned to a retained property, self.stringProperty; this has the effect of (once again) incrementing the retain count;

So, it is true that autorelease adds some "ambiguity", because the object will be released at a time that you don't know precisely (but pretty soon anyway), but assigning to the retain property will increase the retain count so that you have full control over the lifetime of the object.]

If you don't like the autorelease you can always use a constructor method which gives you back an autoreleased object, when available:

self.stringProperty = [NSString stringWith...];

or assign directly to the ivar:

stringProperty = [[[NSString alloc] initWith...] autorelease];

because by accessing directly the ivar you are bypassing the setter and getter. Anyway, do the it only in this case (IMHO) to avoid ambiguities.

More in general, the autorelease glitch is the only drawback that using properties has over directly accessing the ivars. The rest are, IMO, only advantages that in many cases will save your life, and if not your life, a leak or a crash.

There is nothing you cannot do with directly accessing the ivars and taking care of when it is necessary to release before assigning, or not forgetting to set to nil after releasing, etc., but properties will do that easier for you, so my suggestion is simply use them and accept the autorelease shortcoming. It's only a matter of getting the basic "idioms" right.

sergio
  • 68,819
  • 11
  • 102
  • 123
  • thank you again, one scenario is I want to keep a xmldoc file always in memory between 2 internet conenction actions, so I may do other things in other methods other controllers but still want to keep my read/write access to that xmlDoc until next connection. and when the time comes I want to release or nil it and create another one with the new connection. when it is autorelease I feel like it maybe gone sometime when I still need it, what do you think? – Spring Aug 04 '11 at 15:48
  • 1
    Don't worry about this, you have full control over an autoreleased object if you assign it to a retained property. See my last edit in the middle of the text, I hope it can make you convinced of that... :-) – sergio Aug 04 '11 at 16:15
  • tnx for great answer,and when I nillify that property somewhere probably object will be released – Spring Aug 04 '11 at 22:16