Search code examples
objective-ccocoamacosgnustep

key-value coding and to-many relationships


I'm a bit confused with key value coding and to-many relationships. I've read that when having such relationship I should use [object mutableArrayValueForKey:@"key"]; to retrieve the mutable array that holds the objects in that ordered relationship.

What I don't understand is what's the difference between mutableArrayValueForKey or just valueForKey.

Let me illustrate with an example (array is an NSMutableArray of self setup as a property):

id array1= [self valueForKey:@"array"];

NSLog(@"first element %@",[array1 objectAtIndex:1]);

id array2 = [self mutableArrayValueForKey:@"array"];

NSLog(@"first element %@",[array2 objectAtIndex:1]);

Both calls return exactly the same. In that case, what is the benefit or different of the second one?

Cheers!


Solution

  • mutableArrayValueForKey does not return "array", it returns a proxy for "array." You can see this if you print out the classes:

    NSLog(@"%@", [self.array class]);
    NSLog(@"%@", [[self valueForKey:@"array"] class]);
    NSLog(@"%@", [[self mutableArrayValueForKey:@"array"] class]);
    

    This prints:

    2010-02-24 20:06:44.258 Untitled[25523:a0f] NSCFArray
    2010-02-24 20:06:44.275 Untitled[25523:a0f] NSCFArray
    2010-02-24 20:06:44.276 Untitled[25523:a0f] NSKeyValueSlowMutableArray
    

    Read over the documentation for mutableArrayValueForKey for details on how that proxy works. In this particular case, you happen to have a real NSMutableArray as an ivar. But what if there were no such ivar? You can implement KVC without an ivar backing the property, with methods like countOf<Key> and objectIn<Key>AtIndex:. There's no rule that there be an actual "array" ivar, as long as you can return sensible results to the KVC methods.

    But what if you want to expose an NSMutableArray interface, but you don't have a real NSMutableArray? That's what mutableArrayValueForKey is for. It returns a proxy that when accessed will translate into KVC methods back to you, including sending you mutating to-many methods like insertObject:in<Key>AtIndex:.

    This even happens in the case that you have a real ivar (as in your case), you just don't notice it because the proxy behaves so much like the real object.