views:

375

answers:

5

This little bit of syntax has been a bit of a confusion for me in Objective-C.

When should I call self.myObject vs just calling myObject.

It seems redundant however they are not interchangeable.

Would someone please enlighten me?

A: 

You should almost never call property accessors from within the implementation of the same class. Instance methods of the class have convenient access to the internal state, so it usually makes sense to access that state directly.

If you're using synthesized accesors, then calling them just adds (probably) unnecessary overhead. If the accessors have a more complicated implementation, then you're just obscuring the purpose of the code.

Finally, some folks who are new to Objective-C use the self.property syntax and synthesized accessors to try to avoid having to understand Cocoa memory management. You really do need to learn how it works, so trying to avoid doing so is counter-productive.

Mark Bessey
Just because you can fiddle with the object's internal state all willy-nilly doesn't mean you should. And just because you understand how memory management works doesn't mean you'll do it perfectly all the team. Duplicating your memory management responsibility among a bunch of methods is asking for bugs.
Chuck
I respectfully disagree. If your classes have a lot of @synthesize'd accessors, then they're probably poorly designed. If you've implemented non-trivial accessors, then you want to be careful about using them appropriately.Property accessors are intended to be used to create an *external* interface for your class. sometimes, it'll make sense for your class to use it's external interface internally, but often, that's unnecessary (or counter-productive).
Mark Bessey
In any case, if you really want to use the accessors, then using the "self." syntax just obscures what's going on, so you should use explicit messaging anyway. If you're setting a property, "[self setFoo:value]" is just 5 characters longer than "self.foo=value". For read access, the difference is even less. You're only going to write the code once, so you should try to make it clearer what's going on when you (or someone else) reads it later.
Mark Bessey
+3  A: 

If you're just accessing them, there's not much reason to use self.member. If you're doing assignment, it's good if you're doing more than the simple @property (assign) parameter--for instance, retain, copy, etc, so it can save on code you're writing. An example:

myObject = anotherObject;
self.myObject = anotherObject;

The second choice will ensure that you're actually assigning the object the way you want (getting a copy, increasing the retain count, etc.). It's no different from [self setMyObject:anotherObject].

Since the dot-notation gets substituted for a message by the compiler (similar to how x[5] becomes *(x + 5*sizeof(x)) in regular array work), there's no overhead or extra efficiency in using dot-notation over regular messages.

Cinder6
+1  A: 

If you're using Core Data, you should essentially always use the accessors, since some properties may not be loaded from the persistent store until needed. (Assuming you're using a SQLite store, anyway.)

If you're not using Core Data, you're generally safe to just use myObject directly if you're only reading the value. If you're modifying the value of myObject, you need to use the accessors in order to make sure that any other objects observing the value of that property are properly notified. In other words:

// Not changing the value of myObject, so no accessor needed
[someMutableArray addObject:myObject];  

// Changes the value, so you need to use the accessor
self.myObject = newObject;     
[self setMyObject:newObject];  // Exactly identical to the previous line.

In general, though, there's very little overhead; I prefer to always use the accessors, even within the same object. (Of course, there's the argument over using them in initializers, but that's a separate issue.)

BJ Homer
+3  A: 

Hrm, I cannot say that I agree with Mark or Cinder6.

Well, I agree in the first part. :-) self.foo is invoking the -foo method. Plain foo is accessing the foo ivar.

In most circumstances you should always go through your methods. They're there to abstract you away from the actual storage, and away from any other behavior that might be necessary. Think about what happens if you later subclassed your class. For the most part you want to be calling your own public methods in the places where you access the functionality they cover.

The exception is in object init and teardown, and within property accessors themselves when you don't synthesize them. During object init and teardown, you do not want to invoke subclass implementations of methods, because those methods should not have to deal with your object in its partially set up state.

Ken
A: 

There is not cut and dried answer. However, remember that premature optimization is bad. In Cocoa on the Mac, or on the iPhone, the use of accessors/properties is required to be KVO-conformant. KVO conformance is necessary for Core Data and Cocoa Bindings to function automatically. In Core Data, it is not only necessary to ensure KVO when modifying properties, but also when accessing them.

It is also best to use accessors/properties when you want to ensure property memory management behaviour, which is to say, always when setting an ivar to use the setter or dot notation, and depending on which memory management pattern you follow, to always use accessors/properties when getting an ivar.

There are a number of different memory management patterns. All of the non-broken ones ensure that an object returned by an accessor will survive to at least the end of the current autorelease scope. Meaning, either the object is explicitly retained and autoreleased in the current autorelease scope. The method recommended by Apple does this explicitly in the getter:

  • (id)foo {return [[foo retain] autorelease]; }
  • (void)setFoo:(id)aFoo { if(! [aFoo isEqual:foo]) { [foo release]; foo = [aFoo retain]; } }

It's implied that's the pattern they follow in their synthesized accessors. Personally, I prefer to autorelease in the setter:

  • (id)foo {return foo;}
  • (void)setFoo:(id)aFoo { [foo autorelease]; foo = [aFoo retain]; }

This autoreleasees the old value before replacing it with the new value. This has exactly the same effect as retaining and autoreleasing in the getter, but requires the object to only be added to an autorelease pool once. Most of the time it has a retain count of one and is not autoreleased, so it won't go anywhere no matter what happens. If the property is replaced during some code that is still holding on to it (such is in a delegate callback), it won't disappear out from under it.

What this means is that using accessors/properties will give you confidence that your objects will be around as long as you need them to be without some other part of the code releasing them out from under you.

The last and best reason to always use accessors/properties is that it makes one fewer assumption for each property: that there is an underlying ivar for that property, and that is has the same name (I guess that's two assumptions). Perhaps in future you will want to replace an ivar with a derived accessor. The property notation will still work. Perhaps you want to re-name the ivar; the property will still work. Fortunately, refactoring in Xcode can usually be relied upon, but why even bother?

The point of object-oriented programming is to use the interfaces defined on the class. There is no good reason (though there are many prejudicial and rationalized ones) for a class to ignore its own interface. Every method except the accessors themselves should, in the general case, treat the object as sacrosanct and its internal state as private. Write every method as if it were in a category or on a sub-class, and treat ivars as private state, unless specific design needs direct you do otherwise. There are plenty of good reasons to directly access ivars, but they are determined on a case-by-case basis.

BoredAstronaut
Your getter/setter methods are not identical to Apple's. Your getter is basically the one you'd use for an "assign" property and the setter is for a "retain" property. I'm sure it works most of the time but I think it will come unstuck if you start using your own autorelease pools. Best to stick with the conventions used in the rest of Cocoa.
Stephen Darlington