iosobjective-ckey-value-observingkvc

Objective-C - How does KVC work under the hood?


I am working with KVC and I am wondering how it works under the hood.

Since it uses keys and values, I could assume that the self of each object holds a dictionary with keys = properties name and values = setters . So when I call [self setValue:aValue forKey:@"aProperty"] the object is getting a hash value from the key which is pointing at the setter method.

All of this of course is speculation and how I would implement it with my knowledge.

Is that how it works under the hood?


Solution

  • Conceptually you're on the right track, although it's a bit more complex.

    First of all, keep in mind that Objective-C is a dynamic language. Essentially, each class maintains a mapping of method names to their actual implementations (which are just C functions). This is akin to the dictionary you talk about, although it is managed by the Objective-C runtime itself.

    This mapping is used every time a method is called. For example, let's say you have this bit of code:

    [obj doSomething];
    

    What really happens is that, at runtime, the Objective-C runtime searches obj's method mapping for an entry called "doSomething". This returns a function that the runtime then calls, passing in obj as the first parameter to that function.

    Because methods are dispatched at runtime, Objective-C provides a number of ways to call functions using strings. (This is akin to doing something like getattr(obj, "doSomething")() in Python, if you're familiar with Python.)

    The Objective-C runtime itself also tracks the names of instance variables and where they are actually located in memory, relative to an object.

    This is how KVC is able to do its thing. When you call:

    [obj setValue:@"value" forKey:@"property"];
    

    The KVC runtime uses the Objective-C runtime to first look for a method called setProperty. The runtime fetches the function corresponding to that method, and the KVC machinery can then call that method, passing obj and @"value" as the parameters to that function.

    What if a method can't be found? Well, then the KVC machinery looks for an instance variable with the same name, using a function from the Objective-C runtime like ivar_getOffset or the like. Probably at some point it uses a function like object_setIvar to set the instance variable. (This is speculation, but I think it's a pretty good guess as to how KVC works vis-à-vis instance variables.)

    If KVC fails to find both a method and an instance variable, it calls setValue:forUndefinedKey: or valueForUndefinedKey:, which can optionally be defined on a class to dynamically handle properties.


    In a nutshell, you have the right idea, but the mapping of property names to methods (or ivars) is done by the Objective-C runtime, and possible thanks to the dynamic nature of Objective-C.


    Also note that KVC is fairly straightforward in how it works. KVO gets a bit more complicated.