views:

195

answers:

4

I gather that in Objective-C I must declare instance variables as part of the interface of my class even if these variables are implementation details and have private access.

In "subjective" C, I can declare a variable in my .c file and it is not visible outside of that compilation unit. I can declare it in the corresponding .h file, and then anyone who links in that compilation unit can see the variable.

I wonder if there is an equivalent choice in Objective-C, or if I must indeed declare every ivar in the .h for my class.

Ari.

A: 

To restrict access, you can use the @private or @protected keywords:

@interface Foo : NSObject {
    @private
    int barPrivate;

    @protected
    int barProtected;

    @public
    int barPublic;
}
@end

EDIT: Scratch everything, turns out I really need some sleep.

Can Berk Güder
That's right, you can't add instance variables with a category.
codewarrior
Yep, I remembered that right after I posted the answer.
Can Berk Güder
Create more than once instance with different values for `bar` and you'll see — `bar` is a global variable.
Chuck
@Chuck: see my last edit. 4:33 AM, CBG signs off. Note to self: review all the code you've written in the last 2 hours when you wake up.
Can Berk Güder
+2  A: 

Ari,

A good reference to how to accomplish "invisible" instance variable declarations can be found here with credit respectfully given to Matt Gallagher.

Hope it helps, Frank

Frank C.
Right. The bit that actually answers my question is that I can put part of the @interface in my .m file. Thank you for the pointer.
iter
+2  A: 

The instance variables have traditionally been needed to determine the size of the class. It's always been poor practice to directly access the ivars, and that isn't the point. In the modern runtime, this is less necessary, but at any rate, it isn't an abstraction leak unless clients are relying on the class's ivars, which should be impossible since you're declaring them as @protected or @private, right?

Chuck
Thank you for pointing out the original positive intention of explicitly enumerating ivars. I have been using truly dynamic languages (Python, Lisp) for so long, I forget that some languages want to know sizes at compile time. In many ways learning Objective-C is like a trip down memory lane. Or down a mine shaft: I get to see all the different strata of sediment that accumulate in the language over its lifetime.
iter
@iter: The need isn't even really there in Objective-C anymore. The modern runtime works much like Python's, where instance variables can be assigned all willy-nilly without being declared in a header, but the language still carries around the syntax of its past.
Chuck
I think I may have run into this the other day, though, when I started to run into intermittent objc_msgSend_fixup errors. I'm not 100% sure, but the problem disappeared when I removed the object_setClass I used to cast an object to a custom class with added properties.
Elise van Looij
@Elise van Looij: That's because `object_setClass` is not a cast and it's not at all the right way to do that.
Chuck
Right. Well, that helped.
Elise van Looij
Note that I specifically said you can assign arbitrary variables on an object, not that you can safely make an object of one class into an object of some other arbitrary class. That's the part that won't work.
Chuck
A: 

ivars are @protected by default (although @private and @protected don't guarantee that other classes can't access them--you can always access ivars with getValue:forKey:). You should never directly access ivars from other classes directly in any case--the "choice" is whether or not to expose the ivars as properties (you just have to rely on all classes following the convention to not access ivars directly).

In the new objective-c runtime, you don't have to declare ivars at all, since they can be synthesized at runtime, but unfortunately that doesn't work with the iPhone simulator, so for now, it's best just to declare all the ivars in the .h file.

eman
I worry less about preventing the client code from doing something strange with my code and more about telling the client programmer more about my implementation than he wants to know.When I read a .h file, I want to learn the "outside" shape of the library I'm using. If I want to know its inner workings, I read the .c or .m as the case may be. I like to keep these two distinct and separate.
iter
I agree--it's annoying that the ivars are in the .h file, but as mentioned above, I think it's for the benefit of the compiler.
eman