5

When using Objective-C properties can you stop creating instance variables altogether or do explicit instance variables (not the ones synthesized by the properties) still serve a purpose where properties would be inappropriate?

Besi
  • 22,579
  • 24
  • 131
  • 223

4 Answers4

13

can you stop creating instance variables altogether

No, you can't (in a sense). What you can do is stop declaring them if you have properties. If you synthesize a property and you haven't declared the instvar, it will get declared for you, so you are creating an instance variable, just not explicitly.

do they still serve a purpose where properties would be inappropriate?

It used to be the advice to create properties for everything because having synthesized properties does almost all of the retains and releases for you. However, with ARC that reason for using properties to wrap the memory management has gone away. The advice now (for ARC) is, I believe, use properties to declare your external interface, but use direct instance variables where the variable is part of the object's internal state.

That's a good reason to adopt ARC: properties revert to their true purpose only of being part of the class's API and it's no longer necessary to use them as a hacky way to hide memory management work.

Edit

One more thing: you can now declare instance variables in the @implementation so there is now no need to leak any implementation details in the @interface. i.e.

@implementation MyClass
{
    NSString* myString;
}
// method definitions
@end

And I'm pretty sure it works in categories too. - see comment below

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • 3
    you can't add ivars and properties to categories, as objc-runtime allows only to add ivars during class-registration. You can't alter a memory-layout of a class after it is registered with the runtime. – Jonathan Cichon May 03 '12 at 13:50
  • you *can*, however add ivars to a class-extension (closely related, but different from a category) – Sean May 03 '12 at 13:56
  • 1
    @Jonathan Cichon: Thanks for that, just tried it and it turns out you are correct about instance variables but wrong about properties. You can add properties but you cannot `@synthesize` them. – JeremyP May 03 '12 at 13:57
  • @JeremyP as long as you can't synthesize them, i can't really see a use for properties in categories. I think `@property` still just adds the getter/setter declaration to the interface. – Jonathan Cichon May 03 '12 at 14:00
  • 2
    @JonathanCichon, non-synthesized properties in categories are very useful and common. You just have to write a custom getter/setter. See this blog post for my most common use of this technique: http://oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/ – Rob Napier May 03 '12 at 14:01
  • 1
    @Jonathan Cichon: That's a misunderstanding, of properties I'm afraid. A property is part of the API, the implementation is up to you and `@synthesize` just automates one of the most common implementation patterns by adding a standard set of accessors. There's nothing to stop you from defining your own different accessors. – JeremyP May 03 '12 at 14:06
  • @JeremyP: I meant `@property` does no real magic without `@synthesize` it 'only' helps to keep your code clean. @Rob Napier. I use a similar technique to extend my classes during runtime. I wrote a ruby-like module quite a while back. – Jonathan Cichon May 03 '12 at 14:20
10

I recommend declaring everything as properties and avoiding manual ivars altogether. There is no real upside to manually creating ivars. Declare public properties in your header @interface, declare private properties in a private class extension in your .m file.

To some of JeremyP's points, internal use of accessors still has significant value under ARC, even though memory management is no longer a significant concern. It ensures that KVO works properly, subclasses better, supports custom setters (particularly for things like NSTimer), supports custom getters (such as for lazy instantiation), etc. It is exceedingly error-prone to have a mix of accessors and ivars. It's far too easy to forget which you need to access in which way. Consistency is the hallmark of good ObjC.

If you absolutely must declare an ivar for some reason, then you should do it in the @implementation block as JeremyP notes.


UPDATE (Oct-2013):

Apple's guidance (From Programming with Objective-C: Encapsulating Data):

Most Properties Are Backed by Instance Variables

In general, you should use accessor methods or dot syntax for property access even if you’re accessing an object’s properties from within its own implementation, in which case you should use self:

...

The exception to this rule is when writing initialization, deallocation or custom accessor methods, as described later in this section.

Community
  • 1
  • 1
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • KVO is not important for something that is internal only. Neither is subclassing. Nothing that is part of the implementation of a class should leak out, even to subclasses. This is the hallmark of good OOP. – JeremyP May 03 '12 at 16:22
  • 1
    KVO notwithstanding (though self-observation is occasionally used), since you often require accessors on private properties (lazy instantiation, thread-safety, etc.), and using them is simple and cheap, you should always use them except when there is a strong reason not to (i.e dealloc). Sometimes using ivars and sometimes using accessors is error-prone and difficult to audit for correctness. – Rob Napier May 03 '12 at 16:34
  • How do you do lazy instantiation without an instance variable? I'll repeat: the official line as reported on the Apple list is to use instance variables for internal state when you have ARC but to use properties for everything if you are using traditional reference counting. – JeremyP May 04 '12 at 09:23
  • @JeremyP, just curious, where are the apple docs regarding this? – Alex311 Feb 04 '14 at 20:40
  • @Alex311 I don't think I've ever seen anything official from Apple. The docs I was referring to was an email to the Objective-C list by an Apple employee. – JeremyP Feb 04 '14 at 20:51
  • The link to Apple's official recommendation is in the answer (UPDATE (Oct-2013)). – Rob Napier Feb 04 '14 at 21:09
0

This question was addressed before here

When you use synthesize the instance variables are handled and instantiated for you. If you're using Lion with the new version of XCode also take a look at the various properties in ARC in Transitioning to ARC

Community
  • 1
  • 1
lukecampbell
  • 14,728
  • 4
  • 34
  • 32
  • 1
    I don't think it is the same question, but I updated my question to hopefully make it more clear. – Besi May 03 '12 at 13:38
0

you can always access properties from outside. So if you want a variable only to be read from inside a class you still have to declare a iVar. Also accessing a public ivar with object->ivar is slightly faster than using a method-call.

Jonathan Cichon
  • 4,396
  • 16
  • 19
  • 2
    This is not true. What if you declared the property in the .m file? – Martin May 03 '12 at 13:39
  • you right you can hide the property altogether, but than you can not access it from outside your m-file, for example a subclass. – Jonathan Cichon May 03 '12 at 13:42
  • 1
    @Martin: As the property is implemented as a pair of methods, it's always available at run time no matter where it was declared. – JeremyP May 03 '12 at 13:42
  • @Martin: which part were you not aware of? That properties are really a setter and a getter method or that methods are always public effectively? – JeremyP May 03 '12 at 13:48
  • @JeremyP was not aware that they were always publicly available. – Martin May 03 '12 at 13:51
  • 1
    While directly grabbing internal ivars with `->` is faster than a setter, it is almost never the correct answer. By the time you're doing that kind of optimization, there is almost always a better optimization you should have done instead. This is a very dangerous technique and not something for general use. – Rob Napier May 03 '12 at 13:58
  • @Martin: It's because of dynamic dispatch. You can send any message to any object, it's just that some objects choose to deal with some (most) messages by throwing an exception. Objects can't tell where a message has come from so they can't respond properly some of the time and with an exception at other times. – JeremyP May 03 '12 at 14:01
  • A common technique is to place your "protected" methods for subclasses into a separate category in its own header file so that subclasses can easily import it. – Rob Napier May 03 '12 at 14:07