Accessing an Objective-C ivar from outside the class at runtime - objective-c

I know this idea completely breaks encapsulation, but say I have the following class extension:
#interface MyClass () {
int reallyImportantIvar;
}
// ...
#end
Normally, the class behaves like it should inside the Objective-C layer - sending and receiving messages, etc. However there is one ('public') subroutine where I need the best possible performance and very low latency, so I would prefer to use a C method. Of course, if I do, I can no longer access reallyImportantIvar, which is the key to my performance-critical task.
It seems I have two options:
Make the instance variable a static variable instead.
Directly access the instance variable through the Objective-C runtime.
My question is: is Option 2 even possible, and if so, what is its overhead? (E.g. Am I still looking at an O(n) algorithm to look up a class's instance variables anyway?)

Actually, if the definition of the C function is within the #implementation block of the class, then it can access private ivars on that class via the usual object->someIvar notation. So while you can use the runtime to access this, I don't think you need to. Just implement the function within the #implementation block of the class in question, and you should be just fine.

Another alternative is to declare the ivar as #package or #public. Then code outside your class's implementation that can #include that class extension can use the ivar.
#public allows any code to do so. #package limits the scope to the same binary as the class's implementation, which is usually appropriate when writing a shared library.

The Objective-C runtime includes the object_getInstanceVariable() function. I believe that's what you're looking for. I haven't checked in detail, but I don't believe there is any big difference between accessing it that way and the normal way.

Related

Inline accessor (getter/setter) methods in Objective-C

Data encapsulation, or as I like to call it, Who owns it and who needs to know about it, makes up a lot of object-oriented programming. The who needs to know is often satisfied by accessor methods, but these get to be pretty expensive if they all result in an objc_msgsend just to read a variable. C++ answers the problem with inline methods - use the "inline" keyword before the definition, or define the method within the class declaration, and the compiler puts the accessor code within the caller's code, saving the overhead associated with an actual function call.
class IntWrapper {
public:
int getInt() { return anInt; }
protected:
int anInt;
};
Similar syntax is rewarded by a complier error in Objective-C. Having searched the language guides in Xcode ("[Object-Oriented] Programming with Objective-C"), I don't see any relevant reference to "inline" of a method. Is there such thing as inline in Objective-C? Is it called something else? If anyone could point me to the documentation that references inline, much appreciated.
Using the simple test code:
#interface ClassA : NSObject
{
int anInt;
}
- (int) anInt;
#end
#implementation ClassA
- (int) anInt { return anInt; }
#end
and looking at the assembly of the code that uses it, it looks like about 25 instructions.
All Objective-C methods are dispatched dynamically. They can be overridden by subclasses. They can even be replaced at runtime ("swizzled") by the Objective-C runtime API.
In some ways, they are similar to virtual methods in C++.
As such they can't be inlined.
By the way, the technique you cite violates the principle you cite ("Who owns it and who needs to know about it?"). Putting the implementation in the class declaration exposes implementation detail to clients who don't need to know it. Furthermore, the compiler inlining the code into clients prevents that implementation from changing without a recompile, which is the fragile base class problem. Modern Objective-C avoids the fragile base class problem, which means a framework class can change what instance variables it has without breaking clients.

Protected variables with modern objective-C?

I feel that modern Objective-C encourages using instance variables as properties for memory management and key-value observation. That works fine, and I'm using interface inside implementation file for private variables, like this:
#interface MyClass ()
#property NSObject* myVar;
#end
However, how can I make protected variables? In case above, my subclasses won't be able to see properties declared like that. I can go iVar route, but then it feels off with the rest of the code if private variables are declared like above and protected are iVars.
I've read this solution: Workaround to accomplish protected properties in Objective-C, but it seems to overcomplicate code too much.
Your best option is to use a category in a second header file, e.g. MyClass_protected.h, and include it in the main class and subclasses, as suggested in the solution you link. It's really quite straightforward, not "overcomplicated" at all, just one additional file.
Objective-C has very strong introspection characteristics. No matter how or where you declare a property (or any other function, for that matter), you can access it from anywhere. You will get a compiler warning unless the code you're writing can see the corresponding declaration or implementation (unless you use an introspective method like one of the performSelector... family). The only reasons for the interface are name-safety, type-safety, and preventing compiler warnings. Therefore, you have a few options:
The main class interface
You get implementation safety (i.e. the compiler will give a warning if you don't implement a method). However, every class (that imports yours) will see the methods. You can use a comment to indicate that the method should be protected, but of course no one will see it unless they check the source. I most often use this when I'm the only programmer on a project, as I know what should be protected and what shouldn't.
A category in the same .h file
As above, programmers won't see it's protected unless they check the source, but if they do it will be much more obvious. If you declare this in a named category (#interface MyClass (protected)) you lose type safety, but it's even more clear what you intend. I most often use this to emulate abstract methods - i.e. explicitly not implementation-safe, but should be visible to everyone.
A category in the subclass's .m file directly
It's a bad idea, don't do it. You do only see the methods in the subclass, but you lose implementation safety and it really just feels wrong. I have only ever used this for unit tests, and I eventually migrated those to a separate header.
A category in a separate header (MyClass_protected.h)
The preferred solution, and the closest Objective-C can get to protected methods. It's just one more file, seriously, don't get your panties in a bunch over that. You can use the class extension (they are anonymous categories) and you won't lose implementation safety. It's only visible to classes that include it, which should only be subclasses; the fact that the contained methods are intended to be used as protected should be obvious to all but the most incompetent programmers because of the header name.

When to use instance variables and when to use properties

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?
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
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.
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
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.

Why are Objective-C instance variables declared in an interface?

I'm just getting into Objective-C (Java is my primary OO language).
Defining an object's instance variables in the interface instead of the class seems strange. I'm used to an interface being a public API definition with nothing besides method signatures (not counting constants here).
Is there some reason that state is defined in an interface (even if it is private) and behaviour is defined in a class. It just seems odd that since objects are state+behavior that the definition would be split into two separate places.
Is it a design benefit is some way? A pain in the rear issue that you are just forced to deal with in Objective-C? A non-issue, just different? Any background on why it's done this way?
Or can you put object state in a class and I just haven't hit that part in my book yet?
UPDATE
The answer below was written before the language feature of declaring instance variables in the implementation was implemented. The premise of the question is now no longer valid. As FireLizzard says, nothing needs to go in the #interface that you don't want to be public.
It's a hangover from the fact that Objective-C originated as a fairly thin layer built on top of C. The C way is to define the interface to a module (do not confuse with a Java interface) in a header file and literally include it in each compilation unit. It's akin to automatically copy-pasting the declarations to the top of every compiled file. If that seems primitive, it is because it is, but C is a 40 year old language.
You have to define instance variables - even private ones - in the interface because Objective-C objects are implemented as C structs which are themselves just blocks of memory and named offsets within that block. The struct that represents an object of each class has to include space for the superclass instance variables so subclasses need to know at least the size of the C struct representing the superclass and also the public and protected instance variable offset. That, unfortunately, means that all the instance variables even private ones have to be exposed as part of the external interface.* C++ the other OO version of C suffers from the same problem for the same reasons.
It's a bit of a pain having to write down all the method signatures twice, but you get used to it.
*With the 64 bit runtime, you no longer need to declare the ivars for synthesized accessors in the #interface but since all methods are public, it still means exposing internal state to the outside World, althoug it does alleviate the fragile base class problem.
In Objective C interface does not refer to the instance at all
Brad Cox who designed Objective C decided that the equivalent of C declarations and definitions should be made explicit so each class has a #interface section telling what it looks like externally and an #implementation saying how it is implemented.
Java came along later and changed the object model so that there is only one definition of an object which pulled the #interface and #implementation together. The compiler (and runtime introspection) in effect construct the interface from the code.
The equivalent of an interface in Java is a Protocol in Objective C.
You just get used to it.

Objective-C: Protocols

I'd like an instance variable object to adopt a protocol.
#interface GameScene : Scene <AVAudioPlayerDelegate> {
#private
Layer *content <CocosNodeOpacity>;
}
For example I'd like my Layer object to adopt the <CocosNodeOpacity> so that I can get the methods
-(GLubyte) opacity; //and
-(void) setOpacity: (GLubyte) opacity;
for free. The syntax shown above is invalid. Is it possible to achieve this without creating a new implementation file and creating a custom object? Thanks.
If these are all code you created, the best way to do this is probably to make the Layer class itself adopt the protocol, rather than the variable.
#interface Layer : NSObject <CocosNodeOpacity> { ... }
A key benefit to this approach is that the compiler will check whether you've implemented all required methods in the protocol at compile time, which is generally what you want. Adding the methods in same place as the rest of the standard class implementation is easier to understand (no hunting to find where the magical code came from) and less fragile than using categories (adding the same method via different categories can result in undefined behavior). As a general rule, I only use categories when I have to, such as adding methods to (closed-source) third-party code.
If you don't control the source of Layer, you may have to use this instead when you declare your ivar:
Layer<CocosNodeOpacity> *content;
Note that adopting a protocol allows you to statically type variables with a class type and get compile warnings if the methods aren't present. However, you don't get the methods "for free", since you still have to implement them. Still, judicious use of protocols and static typing can make your code more robust and "fail-fast" than using id as the type for everything. You are to be commended for not just taking the easy way out. :-)
For some details about protocols (including required and optional methods) see this SO answer.
A protocol in Objective-C is similar to an interface in Java. The protocol defines a set of functions and acts as a contract. It's like saying "I guarantee that whatever this object is, it has these methods."
You're pretty close on the syntax in your first code block. It would actually look something like this:
#interface GameScene : Scene <AVAudioPlayerDelegate> {
#private
Layer<CocosNodeOpacity> * content;
}
However, that doesn't save you from having to define the methods for opacity in your Layer class. Using the protocol, you've established that your class will have those functions, but you haven't actually provided them. You'll still need to write the code for them.
I think what you're looking for is an Objective-C category. A category provides a way to extend the functionality of any class by adding methods to it at runtime. They're possible because Objective-C is a completely dynamic language. If you aren't the author of the Layer class and can't easily add the opacity methods to it, a category is the way to go. In some cases, categories are extremely useful - you can add methods to built-in classes, like NSString and NSColor, without having the existing class source.
There's plenty of documentation for categories here on stack overflow. The apple docs are also very good. Here's an article to get you started:
http://macdevelopertips.com/objective-c/objective-c-categories.html