Is it an anti-pattern to use properties everywhere?

I’ve seen questions about whether to always provide accessors for ivars, and recommendations, such as in akosma software’s ObjC code standards, that say Whenever possible, do not specify ivars in the header file; use only @property and @synthesize statements instead.

This isn’t how I work, which led me to ask the question: is this a good recommendation? Obviously the question of whether coding standards are “good” or “bad” is subjective, so what I’m really asking is whether this is something I’d want to do myself.

How I currently work

If I need to be able to see the state of an object from outside that object, I’ll make a readonly property. If I need to be able to change the state of an object then I’ll create a readwrite property. Whether these are synthesised or dynamic properties depends on how I need to compute their values.

If, in implementing a method, I find I need to make use of some object or value that was generated in another method, I’ll create an instance variable to store the value away in the other method so it can be used from this method. I define this ivar in the @implementation of the class.

This effectively acts as a de facto distinction between public and private data. Public data is accessed via properties which can be seen and called from anywhere; private data is accessed via ivars that cannot be seen anywhere except inside the current class (don’t worry about the visibility modifiers @public and friends: because the ivars are inside the implementation even subclasses don’t know what they are).

If I consistently use the property accessors even inside a class, I can see where an object is making use of state that is accessible to the outside world. That can indicate an encapsulation failure, making the class fragile to external prodding. Of course, it’s also expected that objects do get told about the outside world, so it’s not an automatic fail to do this: but it’s useful to be able to see where it happens.

About the “properties everywhere” approach

As I see it, there are benefits and drawbacks to that technique. The pros:

  • Encapsulate memory management. This is less of a benefit with automatic reference counting or garbage collection, but in a manually reference-counted environment you can put the memory management semantics in one place rather than sprinkling your code with retain, release and copy calls.
  • Consistency. Rather than having two distinct techniques for accessing ivars, you have just one.
  • Properties are new(ish), and ivars are old and busted. :-)

The cons:

  • Broken encapsulation. Now all of your ivars have accessors, and as previously discussed here Objective-C doesn’t have method visibility modifiers. All accessors are public (even if declared in the class extension), so any dev armed with a copy of class-dump might decide to change the internal state of your classes.
  • Consistency. This is where it gets subjective, because this was also a pro, but as I said earlier I deliberately make a distinction between internal state and externally-available properties, so making both of these the same is a problem.
  • Writing code you don’t need. Even where you never actually use an ivar outside of the object that owns it, you’re still writing public methods for that ivar.

Conclusion

I’m not going to be adopting the “everything is a property” recommendation, I value the privacy of my parts. I’ll carry on with writing instance variables where I need them, and “promoting” them to properties with accessors where that’s necessary.

About Graham

I make it faster and easier for you to create high-quality code.
This entry was posted in code-level. Bookmark the permalink.

10 Responses to Is it an anti-pattern to use properties everywhere?

  1. Oliver says:

    Coming from Java this is the single most confusing issue for me in ObjC. Java was so nice and easy with its public and private (and complete lack of header files). Still don’t quite know how I can best replicte that… so if I understand you correctly I should use ivars for private and properties for public; will try that.

  2. Ben says:

    Are ivars really going to protect you from someone changing your internal state? https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html class_copyIvarList and object_setIvar imply not…

  3. Ben says:

    PS. Please correct me if I’m wrong, but I don’t think you need @dynamic if you explicitly implement the getter/setter method. My understanding is that this is only needed if you’re adding the methods at run-time.

  4. Hamish says:

    I’m in total agreement with you, as you may remember from NSScotland :)
    I’d just like http://www.openradar.me/radar?id=1358403 to be fixed, then all my code will be as clean as a whistle!

  5. g says:

    But that recommendation is how you work: you never specify ivars *in the header file*.

  6. Graham says:

    Ben, you don’t-currently-need to supply dynamic if you implement the accessors. And yes, there’s always a way around encapsulation; the design I’ve chosen in my code is there to make the intent clear as possible.

  7. mattyohe says:

    Attempts to “protect” against another developer armed with class-dump is a fool’s errand.

    Variables you want accessible outside of your class can be readonly or readwrite in the .h file, and the rest can go in your class extension.

    You get KVC for free.

    No need to write ivars! (obvious)

    We will be getting automatic synthesis of properties at some point in the future.

    Oliver: You should be writing things like this:

    MyClass.h
    @interface MyClass : NSObject
    @property (readonly) SomeObject *anObject;
    @property (readwrite) SomeObject *anotherObject;
    @end

    MyClass.m
    @interface MyClass ()
    @property (readwrite) MyOtherObject *anObject;
    @end

    @implementation
    @synthesize anObject = _anObject;
    @synthesize anotherObject = _anotherObject;
    @end

    There you go. You now have two properties, one that can be only read (anObject) from the outside and another that can be mutated (anotherObject). In the .m file you redeclare anObject as readwrite so you have a setter generated for use inside your class. The underscores you set on the ivars are also a good idea as to signal when you’re accessing them directly.

  8. Graham says:

    There are times you don’t _want_ KVC though. I’d always make accessors KVC compliant, but wouldn’t always make accessors.

  9. In my defense :) I’d say that I don’t say in my coding guidelines that everything should be exposed; I usually define “private” properties in an anonymous category inside the .m implementation file. The .h file only exposes public properties; I just avoid adding the wrapped ivars, which keeps the file shorter and simpler.

    And by the way, thanks for the link :)

  10. dimsumthinking says:

    I currently use properties everywhere – but properties have nothing to do with what I am exposing.

    Most of my classes have class extensions and I begin by declaring my properties there. This is currently possible for outlets as well so I only declare things in my header that I want others to use.

    I frequently expose a property as readonly in the header and redeclare it as read write in the class extension so that it is publicly readable and privately writable. (As Mattyohe showed above)

    There is an issue with subclassing if you do this, however. But there are workarounds for that as well.

    With ARC and the default as strong I probably could use private ivars more frequently but I currently only use them for the occasional BOOL that is serving as a flag or another primitive that I use in the same way.

Comments are closed.