Instance variables declared in ObjC implementation file
Asked Answered
A

3

49

I was watching the WWDC ARC introduction video and I saw something I've never seen in ObjC before when some Apple engineer talked about a Stack example.

The following code was used for a stack example with ARC:

@implementation Stack 
{ 
    // instance variable declared in implementation context
    NSMutableArray *_array; 
}

- (id)init 
{
   if (self = [super init])
      _array = [NSMutableArray array];
   return self;
}

- (void)push:(id)x 
{
   [_array addObject:x];
}

- (id)pop 
{
   id x = [_array lastObject];
   [_array removeLastObject];
   return x;
}

@end

Please note the instance variable declared right after the @implementation directive.

Now the thing that surprised me, is that an instance variable could actually be declared in the implementation file, without it being a static variable. My questions would be the following:

  • Is this some new construct introduced in the SDK for iOS 5 or has this been possible for a long time?
  • Would it be good practice to declare instance variables in the implementation, if the instance variables are not to be accessed outside the object? It seems way cleaner then the use of the @private directive.
Arcadian answered 22/7, 2011 at 4:48 Comment(8)
Do you have a complete, compilable example of this?Radiothermy
The above code should compile just fine with the iOS 5 SDK.Arcadian
How about instead adding the iVars in a class extension?Estefanaestel
@OscarGomez Trying to declare ivars in an extension gives an error in the current version of Xcode with Clang: "Instance variables may not be placed in class extension". Was this previously allowed?Grot
@Grot Mmm it allows me to do it on iOS are you using Mac OS?Estefanaestel
@OscarGomez Yes, on Mac OS.Grot
@Grot I looked it up online, it seems like it only works on iOS for some odd reason.Estefanaestel
@OscarGomez Interesting, good to know. Wonder why.Grot
K
41

This is indeed a new language feature, and if you must declare your ivars (rather than simply declaring properties and letting the compiler generate ivars for you) it's a good practice. Your header files in theory should only expose public interface for your classes; everything else belongs in the implementation.

One caveat is that implementation-file ivars are not visible to subclasses, which can occasionally be a little bit awkward if you have manually generated setters and getters that you need to subclass.

Kill answered 31/7, 2011 at 18:12 Comment(7)
Say I created a class "A" that only declares its ivars in the implementation file (for encapsulation), but I want to make a mutable subclass "MutableA". How can I gain access to the implementation ivars in A? Note: there are no properties nor getters/setters for these ivars.Horsepower
An Apple engineer told me about the new feature, and recommended I use it. Kind of forgot about it until looking at NSAttribututedString.h and could not find the ivars. The Objective-C topic "Defining a Class" has been updated accordingly, and refers to declaration of ivars in the interface as "historical" As for visibility in subclasses - do subclass implementations just use accessor functions?Candless
@Candless Yes, though I think it's still pretty common to use header declarations (or a mix of header and implementation declarations).Kill
@SeamusCampbell: Above code will work in iOS4.0?. I have checked with deplyoment target4.0 and it's working but at runtime will it cause any issue?Indicant
It's a compiler feature and works fine with deployment on iOS 4 with all of the SDKs released since iOS 5.Kill
How does this compare to declaring ivars in the extension (i.e. @interface MyClass () { ... })? It also allows you to not declare ivars in the header.Soubise
Trying to declare ivars in an extension gives an error in the current version of Xcode with Clang: "Instance variables may not be placed in class extension". Was this previously allowed?Grot
S
18

Declaring iVars inside the implementation is definately a new construct in objective C. You need to be using xcode4.2 and have the LLVM compiler selected in your build settings. The idea is to keep your header files cleaner. You can list your ivars inside curly braces like this example;

@implementation MyClass {    
  int var1;
  int var2;
}

The answer given by Rahul is not really correct, although you can delare variables in the way he says they would be looked upon as static by the compiler. Probably for the cases in which he used them it didnt matter.

Saccule answered 3/8, 2011 at 12:28 Comment(1)
You also need to be eligible for the "Modern" Objective-C runtime, which according to developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/… is available on iOS, and OS X 10.5 and later 64-bit. OS X pre-10.5 and OS X 32-bit use the legacy runtime.Rossini
S
3

I am new to Objective C, and I found the practice of declaring ivars in the header very very odd. It means declaring the internal state of an object in its public header, which defies the concept of encapsulation.

For example say you own an IPad. Apple does not want you to break the IPad open and pry around , and mess with the elements inside. If they want you to modify something, the IPad will have a setting that let you change that.

Similarly I dont want other programmers to see the ivars of my objects. Its the internal state of my object. If I want you to acess the internal state, I will declare properties for it.

So, as in other languaes, I would hide my ivars inside the implementationfile, and not declare them in the header.

Declaring ivars in the header just strikes me as very very odd. Those ivars are implementation specific, and should simply not be part of the header file.

Swiftlet answered 9/10, 2012 at 9:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.