13

I have searched many questions on ObjC accessors and synthesized accessors to no avail. This question is more of a "help me settle an issue" question; I don't expect one answer, but I'm rather looking for experts to weigh in on the argument.

In a Cocoa Touch class, I would write some code like this (where soundEffects is a synthesized NSArray property):

id foo = [self.soundEffects objectAtIndex:1];

A colleague asked me to explain why the above is any better than this line:

id foo = [soundEffects objectAtIndex:1];

Well, functionally, it's no different.

My arguments for the former are as follows:

  1. self.soundEffects tells every other coder working on the code that this is an iVar, not a locally scoped variable.

  2. If we ever needed to, we could put custom logic in the soundEffects getter accessor.

  3. For no concrete reason, it "feels" like the right thing to do after working in Obj-C for a year.

He accepts arguments #1 and #2 as valid, but also gives the counterpoint:

  1. Isn't this just code bloat?

  2. Shouldn't a class be allowed to talk to its own iVars directly without having to call a method (the getter) on itself?

Any takers?

makdad
  • 6,402
  • 3
  • 31
  • 56
  • 2
    I think that self.soundEffects is better because other objects can know when the value changes through key-value coding, but otherwise they don't know that it has changed... – Tom H Aug 16 '10 at 14:56
  • You mean key-value _observing_, but that wouldn't take effect here anyways, @TomH. `[self.myMutableArray addObject:anObject]` doesn't notify observers; only `setMyMutableArray:` does. – jscs Jun 16 '14 at 19:21
  • Ah yes, you're correct on both fronts. But I believe [It's been a while!] the point still stands for quite a few uses where this question may come up, even if not relevant for the particular example he used. – Tom H Jun 17 '14 at 20:07

4 Answers4

9

I have personally settled on using an underscore prefix for ivars, and this kind of synthesize

@synthesize name = _name;

That way I don't mix them up. The major issue with not using self is that this code

_name = ...

is very different from

self.name = ...

When the @property uses the retain option. The first does not retain the object, and the second calls the synthesized setter that retains.

The only time it makes a big difference is with assigning, so I tend to use self. all of the time so I make sure I do it on assigns.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • 3
    Be careful if you're using that leading underscore with Cocoa frameworks. Apple reserve the use of the leading underscore for class iVars and you may run into trouble picking an identical name for an iVar of a subclass. – ohhorob Aug 16 '10 at 17:29
  • 1
    +1 It's *very* important to recognize that when assigning properties, retain does not get called without using the "self." syntax. – meddlingwithfire Feb 01 '12 at 17:01
  • @meddlingwithfire I'm new to Obj-C but are you guys serious... `propertyName` is functionally different than `self.propertyName`? Even in modern Obj-C? That just spells all kinds of trouble... – devios1 Mar 14 '13 at 00:00
  • 1
    @chaiguy Yep. Calling the propertyName alone is different than calling it using the self.propertyName. That's why it's very important. I agree that it spells all sorts kinds of trouble; it took me forever to debug code that looked fine by just glancing at it. – meddlingwithfire Mar 16 '13 at 23:09
  • @meddlingwithfire If I *don't* have an instance member called `propertyName` is it then interpreted as a property access (like `memVar` is treated as `this.memVar` in langs like C#?) or will it simply not be able to resolve `propertyName` without the `self.`? – devios1 Mar 17 '13 at 21:45
5

Your point 1 is not quite right: self.soundEffects is not an ivar, although it may happen to give you something which is -- as it does in the case of your synthesized NSArray, at the moment.

This in turn implies that your point 2 is the crux of the matter -- if you route all access through the accessor, then everything is nicely encapsulated and you're free to modify the implementation later without having to worry about side effects.

It's also good practice for when you use the mutator, so you maintain consistent memory management.

For the most part, I'd say it's advisable to route through self.property for everything that is a property, and restrict direct ivar access to things which are strictly internal. However, I'll admit that in some cases -- especially for things that don't use retain/copy semantics -- it can be more of a style preference.

walkytalky
  • 9,453
  • 2
  • 36
  • 44
  • 1
    "Strictly internal" is I guess the issue. When using a getter inside of the same class, some can argue that a class needs to know its own implementation. A functional programming fan, I prefer to keep it even tighter than that (methods are as self-reliant as possible), so that's why I prefer the self.something syntax. – makdad Aug 17 '10 at 01:24
4

using something like self.variable = nil makes the variable go through its setter and therefore gets memory managed for free. if you just use variable = nil for instance in a dealloc method, it will cause a leak since it is not actually going through the synthesized setter for the variable and decreasing the retain count. See this post memory leak with self.

For this reason, it is advisable (i believe) to always use self. when dealing with instance variables that you own as far as memory management is concerned.

Community
  • 1
  • 1
Jesse Naugher
  • 9,780
  • 1
  • 41
  • 56
  • Thanks. We're well convinced about using self.property = nil instead of just property = nil. What I'm more interested in is the getter side of things. Any thoughts? – makdad Aug 17 '10 at 00:58
  • Its actually considered to be better to release your instance variables directly in dealloc rather than using property accessors. – Luke Redpath Aug 17 '10 at 17:58
  • Luke- would love to know why. Any ideas? – makdad Aug 20 '10 at 00:54
  • @phooze I *think* the issue is that property accessors can potentially trigger notifications, which is undesirable in an object you are in the process of deallocating. – walkytalky Aug 20 '10 at 23:07
  • Can't see the point of setting an ivar to nil in [dealloc]. If you want to release memory in [dealloc], say it like you mean it. You seem to be relying on a side-effect of passing nil to a synthesized method, and on the property being a (retain) property. It may achieve the same result is these conditions are true, but calling [release] directly communicates your intention much more clearly. This is not Java :=) – iter Mar 02 '11 at 20:32
  • `self.variable = nil` works no matter what kind of property it is -- the setter does the right thing. If you release, you are encoding in the dealloc that your property definitely does a retain, which it might not -- what if it's an assign (or you change it). – Lou Franco Feb 08 '12 at 17:47
  • Also, you should always use `@synthesize var = _var` to avoid the bug you point out. This is the preferred Apple style in their current templates. – Lou Franco Feb 08 '12 at 17:48
1

self.soundEffects
sets/gets the instance variable through the setter/getter, and hence if we want to do some custom operations when their value changes, that logic can go in their getter/setter.

Also as per ios 6, the ivar corresponding to

@property (nonatomic)NSArray *propertyName;

will be

_propertyName

so i guess you cant use

id foo = [soundEffects objectAtIndex:1];
anymore.Not sure though.Instead you should use
id foo = soundEffects[1];
Anoop
  • 5,540
  • 7
  • 35
  • 52