I'm interested in how does dynamic typing in Objective-C work. I've been studying the "id" type, I know what it does and how to use it, but I'm curious... How does such functionality get implemented under the hood?
You cannot determine/resolve anything during compile time, only during runtime. I guess it can simply just point to the first byte of some object in memory, but how is the class signature stored? How does it know what is it currently pointing towards and how does it implement various getters for the class of the pointed object?
"Under the hood", so to speak, all Objective-C objects are C structs with a pointer to the Class object that represents their type. An id
is a pointer to the most basic such struct, which looks something like this:
struct objc_object {
Class isa;
}
id
is treated specially by the compiler, in that the compiler doesn't give you any warning that the object may not respond to any selector as it does when you use a more strongly typed variable.
When you call a method on any object, it follows that isa
pointer to the Class object and looks in that Class object to find the implementation function for the selector of the method you tried to call.
To add to Anomie's answer, how a class stores the table of which messages it answers to and which bits of code those messages invoke is entirely opaque. So there's an extent to which nobody can answer exactly how Apple's implementation works, and it's almost certain to differ from GNU's implementation.
However, Apple's Objective-C Runtime Reference explains everything that the runtime can do, at the C level. So you can see there what operations are possible for setting and looking things up. It's a relatively simple system under the hood, primarily just a bunch of dictionaries (in the uninflected sense) that map one thing to another, such as from a selector to an IMP function pointer. If there's an entry in the table for a particular class then the relevant thing is called. If not then superclasses are checked, the standard forwardingTargetForSelector: fallback mechanism is considered, and so on.
Beyond that, more specific comments require more specific questions. There are lots of details like that key-value observing is achieved by a method swizzle (so, the runtime adjusts the C pointer that the class will call for the setter to be one that calls the real setter and informs whoever is observing), but they're all just particular uses of the runtime as documented.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With