开发者

ObjectiveC ivars or @property

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 al开发者_JS百科locate..

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


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:


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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜