In Objective-C, why [object doSomething]? Wouldn’t it be [*object doSomething] since you’re calling a method on the object?, which means you should dereference the pointer?
In Objective-C, why [object doSomething] ? Wouldn’t it be [*object doSomething] since you’re calling
Share
The answer harkens back to the C roots of Objective-C. Objective-C was originally written as a compiler pre-processor for C. That is, Objective-C wasn’t compiled so much as it was transformed into straight C and then compiled.
Start with the definition of the type
id. It is declared as:That is, an
idis a pointer to a structure whose first field is of type Class (which, itself, is a pointer to a structure that defines a class). Now, considerNSObject:Note that the layout of
NSObjectand the layout of the type pointed to byidare identical. That is because, in reality, an instance of an Objective-C object is really just a pointer to a structure whose first field — always a pointer — points to the class that contains the methods for that instance (along with some other metadata).When you subclass NSObject and add some instance variables you are, for all intents and purposes, simply creating a new C structure that contains your instance variables as slots in that structure concatenated on the slots for the instance variables for all superclasses. (The modern runtime works slightly differently so that a superclass can have ivars appended without requiring all subclasses to be recompiled).
Now, consider the difference between these two variables:
(NSRect being a simple C structure — no ObjC involved).
foois created with the storage on the stack. It will not survive once the stack frame is closed, but you also don’t have to free any memory.baris a reference to an NSRect structure that was, most likely, created on the heap usingmalloc().If you try to say:
The compiler will complain about the first, saying something along the lines of stack based objects are not allowed in Objective-C. In other words, all Objective-C objects must be allocated from the heap (more or less– there are one or two exceptions, but they are comparatively esoteric to this discussion) and, as a result, you always refer to an object through the address of said object on the heap; you are always working with pointers to objects (and the
idtype really is just a pointer to any old object).Getting back to the C preprocessor roots of the language, you can translate every method call to an equivalent line of C. For example, the following two lines of code are identical:
Similarly, a method declared like this:
Is equivalent to C function declared like this:
And, looking at
objc_msgSend(), the first argument is declared to be of typeid:And that is exactly why you don’t use
*fooas the target of a method call. Do the translation through the above forms — the call to[myArray objectAtIndex: 42]is translated to the above C function call which then must call something with the equivalent C function call declaration (all dressed up in method syntax).The object reference is carried through because it gives the messenger — objc_msgSend() access to the class to then find the method implementation — as well as that reference then becoming the first parameter — the self — of the method that is eventually executed.
If you really want to go deep, start here. But don’t bother until you have fully grokked this.