Properties vs. Instance Variables
Asked Answered
C

1

5

I am confused as to why some classes declare a property but do not declare an ivar and vice versa.

Is it standard practice when declaring an instance variable to also declare it as a property as well?

Example:

@interface AppDelegate : NSObject <UIApplicationDelegate>
{
    UIWindow *window;
    UINavigationController *navigationController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;

is just standard practice when declaring a class's ivar to make it a property as well?

I get that the @property creates its own elongated setter (and getter with @synethesize) but why does it need to be an ivar as well?

Carpogonium answered 18/8, 2012 at 2:19 Comment(0)
C
14

It doesn't.

In the old days, ivars were required to be declared in the @interface. This is actually still true for PPC and i386 (i.e. 32-bit intel) targets. This is because of the fragile base class problem, which required that all subclasses know the exact size of their superclass. As such, ivars need to be in the @interface or nobody can subclass the class.

With the move to x86_64 and ARM, alongside obj-c 2.0 came a fix for the fragile base class problem. With this fix, class sizes no longer need to be known at compile time but can be deferred to runtime. Therefore, ivars can be declared in other places. Notably, an ivar can now be synthesized from a @property (more specifically the @synthesize line in the implementation). In Clang they can also be declared in a class extension block (which looks like @interface ClassName ()) or directly on the @implementation.

Today, there are 3 reasons why you find ivars declared in @interface blocks:

  1. Old code (or programmers with old habits) that hasn't been updated to take advantage of the ability to hide ivar declarations.
  2. Code that needs to run on PPC or i386.
  3. Code that, for whatever reason, wants their ivars to be public. This should never be the case.

When writing code today that doesn't need to target the old runtime, you should either synthesize your ivars from your properties (preferred), or if you need ivars that aren't tied to properties you should declare them in a class extension or on your @implementation. The primary reason for this is because the header file documents the public API of your class and should not contain anything that's not public. Ivars are not public, and therefore should not be in the header file.

Chevaldefrise answered 18/8, 2012 at 2:31 Comment(9)
Or, if you want to be fancy, you can use OBJC_IVAR: #11999387Linkage
Thanks for the response Kevin. Question: It sounds like declaring an iVar in conjunction with a property is an obsolete methodology. But when should I declare an instance variable and NOT a property? Just for the sake of closure. Thanks!Carpogonium
@GPP: That's somewhat a matter of personal preference. In general I'd say obj-c objects should always be properties. But for C datatypes you may decide that you prefer just using ivars directly. Or you may prefer using properties. That's up to you. Note that if you want a "private" property you should declare it in the class extension in your .m file.Chevaldefrise
@KevinBallard what do you mean by saying: "ivars can be declared in other places." ? I still didn't quite get where the properties are stored ? Aren't they still ivars ? Are they ivars, but their ivar offset will be calculated at runtime rather than at compile time ? I'd like to have a better understanding of what is happening !!!Bantling
@Bantling It means that the compiler can synthesize ivars based on the implementation of the class. On the "fragile" architectures, ivars must be declared in the @interface block, because all subclasses need to know the precise size/alignment of the superclass's memory layout. On the "modern" architectures, this is no longer the case, so the ivars no longer have to be put into the public header file. Ivars are now accessed via a separately symbol that contains the offset of the ivar. So yes, the offset basically is determined at runtime.Chevaldefrise
@KevinBallard what do you mean by saying :"ivars are now accessed via a separately symbol"? How the offset is determined at runtime ? Does dyld do this work ? What does the compiler do with properties ? How about the performance ? Of course the runtime is always slower, than compile time but how much ???Bantling
@Bantling Every ivar gets a hidden symbol of the form OBJC_IVAR_$_ClassName.ivarName in the __DATA,__objc_ivar section. When the obj-c runtime initializes the classes, it updates the value of every ivar symbol with the offset that the ivar has from the start of the class. Every access to an ivar is then rewritten to use that symbol for the offset instead of a compile-time value (although the compiler knows the offset will never change after the first access so it can optimize away redundant loads).Chevaldefrise
@KevinBallard THANK YOU !!! You told me exactly what I was looking for. I've created a class with a property (code) and I wanted to look at this section. I've written the command: otool -s __DATA __objc_ivar test.o in order to see the contents of this section, but all I've got is this: Contents of (__DATA,__objc_ivar) section 0000000000000068 08 00 00 00 00 00 00 00 What are those numbers ? Where did you find that information about __DATA__objc_ivar? I want to understand more the Mach-O binaries , can you advise me something ?Bantling
@Bantling Looking at the section itself isn't going to be very helpful. All you really see is that the first value is 8, which happens to be the value of _OBJC_IVAR_$_TestClass._ivarString, but you wouldn't know this without looking up the address of that symbol. I recommend you take your code and run clang -S main.m. This will emit a file main.s that contains the assembly for your file, and you can see all of the nitty-gritty there.Chevaldefrise

© 2022 - 2024 — McMap. All rights reserved.