57

I see it recommended all over the place when coding for iOS that properties should be used for accessing instance variables because of the benefits this lends to memory management, among other things.

This advice doesn't sit terribly well with me. I find that using properties instead of plain old ivars just takes too much code and I don't really see the benefits if you're comfortable with memory management. Is it really that important? What's your approach to managing instance variables?

nevan king
  • 112,709
  • 45
  • 203
  • 241
Diego
  • 595
  • 1
  • 5
  • 6

4 Answers4

79

It's not really necessary to declare properties for all ivars. A few points come to mind:

  • If an ivar is only going to be assigned to once during the lifetime of the object, you don't really gain anything by declaring a property. Just retain/copy/assign during init and then release as necessary during dealloc.
  • If an ivar is going to be changed frequently, declaring a property and always using the accessors will make it easier to avoid memory management errors.
  • You can declare properties in a class extension in the .m file rather than the .h file if the properties and ivars are meant to be private.
  • When targeting iOS 4.0+, you don't need to declare ivars at all in your header if you define a property and synthesize accessors.

So I generally use properties, but for things like a NSMutableArray that an object allocates during init and uses to hold a bunch of whatevers, I'll use a plain old ivar since I'll never be reassigning the ivar.

Daniel Dickison
  • 21,832
  • 13
  • 69
  • 89
  • 11
    If I have a NSMutableArray as an instance variable, I usually **deliberately do not define a property for it**. This is because, if you pass it to another object as a mutable array, that other object can effectively modify the internal state of the first object without telling the first object. That breaks encapsulation. – JeremyP Feb 17 '11 at 16:21
  • 1
    @DanielDickison How about the other way? I'd like to know some reasons why someone wants an ivar anymore in my Q :: [Why would you use an ivar?](http://stackoverflow.com/questions/9086736/why-would-you-use-an-ivar) – Sam Feb 01 '12 at 16:46
51

While Daniel's answer is correct, I think it misses an important point. Namely:

I find that using properties instead of plain old ivars just takes too much code and I don't really see the benefits if you're comfortable with memory management.

The benefits are consistency; consistent memory management and consistent behavior.

Notably, these two lines of code can actually have extremely different behavior at runtime:

iVar = [foo retain];
self.iVar = foo;

The first is a direct setting of the instance variable and there will be no change notifications. The second goes through the setter and, thus, preserves any subclass customizations upon set and ensures that any observers of the property are notified of the change.

If you are using ivars directly throughout your code (internally to the class -- if you are using ivars of an instance directly from outside that instance, well... any contractor working on your codebase should double their rates ;), then you must either also handle change notification propagation manually (typically by calling willChangeValueForKey:/didChangeValueForKey) or explicitly engineer your application to avoid use of mechanisms that rely upon Key-Value Observation.

You say "takes too much code". I don't see that; in the above two lines of code, the dot syntax is fewer characters. Even calling the setter method using traditional syntax would be less code.

And do not discount the value in centralizing memory management; one accidental omission in a myriad of call sites and crash city.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • 9
    In case people come here in the future and miss the surrounding comments, in iOS 4 you don't have to declare an ivar if you declare a property. This deals with a lot of the problems Diego discusses here. – johnw188 May 05 '11 at 23:05
  • 4
    And with ARC in iOS 5 (and 4, with caveats), you also don't have to declare `dealloc`. – bbum Oct 15 '11 at 16:52
  • 1
    @bbum I'd be interested to get your feedback on a somewhat related question I asked, [Why would you use an ivar?](http://stackoverflow.com/q/9086736/590956) – Sam Feb 01 '12 at 16:43
  • 1
    don't forget to use snippets. @property(nonatomic,strong)<#Class#> *<#name#>; assign shortcut and you are fine – alexhajdu Feb 07 '13 at 23:27
  • 1
    Again With Xcode4.4 and up, we have *Automatic Property Synthesis* so no need to write `@synthesize` any more use it with `_property` or `self.property`. – rptwsthi May 19 '13 at 08:13
  • Yes, but with ARC, `iVar = foo` is less code than `self.iVar = foo`. – ma11hew28 Jun 21 '13 at 17:09
  • OK, @bbum, I'll listen to you. I use ARC now, but I'm still going to start using properties everywhere, even in `init` & `dealloc`. – ma11hew28 Jul 14 '13 at 13:36
  • 2
    @MattDiPasquale It is a matter of taste; I sometimes declare ivars in the `@implementation` and only use them directly. Sometimes I declare `@property`s in a class extension at the top of the .m file. A bit inconsistent, really. I'd use `self.foo =` outside of `init` (and `dealloc`, in MRR). I use `_foo = ` inside `init`. – bbum Jul 14 '13 at 16:46
3

Property are just syntax sugar that avoid you to write same methods over and over. With a property you have a setter that release the old object and retain the new one for free.

Simone D'Amico
  • 2,335
  • 3
  • 17
  • 21
  • I completely understand the concept of a property. My question is why you would want to always use a property instead of an instance variable when an instance variable requires much less code. – Diego Feb 17 '11 at 16:21
  • 3
    KVO-compliance is another important advantage that bbum correctly have underlined. – Simone D'Amico Feb 17 '11 at 18:57
1

For the private fields - I suggest it is safe to use direct ivars only for primitive types (BOOL/int/float etc). I find a good practice wrapping everything related to memory-management in properties - even rarely-used fields. Additional bonus of this approach is that IDE usually highlights direct ivars access differently, so you always have a nice separation of simple scalar fields and object-type fields.

Contrary to this I would strongly discourage any direct ivars in the class public interface. Because of the dynamic nature of language it can lead to runtime errors that are extremely hard to find, localize and fix. Consider the following hierarchy

@interface BaseControl
...
@end

@interface Label : BaseControl
...
@end

@interface Button : BaseControl {
  @public
    BOOL enabled;
}
@end

and a code snippet

- (void)enableAllButtons {
    NSArray *buttons = [self getAllButtons];   // expected to contain only Button instances
    for (Button *button in buttons) {
        button->enabled = YES;
    }
} 

Now imagine there's an error somewhere in -getAllButtons logic and you also get some Label's returned in that array - so those Label class instances will get missing ivar assigned. The fact that may be surprising is that -enableAllButtons will not crash in that case. But at that point those Label instances internal structure is corrupted and this will cause undefined behavior and crashes when they are used elsewhere.

Like some popular problems with memory management (and in general - with dangling pointers) - this kind of problems is hard to find and localize - because the appearance of the error usually is distant (in terms of time, code or app flow) from the place, causing the error. But with that particular problem you even don't have handy tools (like leak/zombies analyzers etc.) to help you localize and fix it - even when you learn how to reproduce it and can easily investigate erroneous state.

Obviously if you use @property (assign) BOOL enabled; you'll get an easy-to diagnose and fix runtime exception in -enableAllButtons.

Max O
  • 997
  • 8
  • 13