views:

63

answers:

2

Hi there,

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!

A: 

The first element is actually objectAtIndex:0, not objectAtIndex:1.

Also, the second method ensures that you can modify the returned array with addObject: and removeObjectAtIndex:, even if the value for the key @"array" is an immutable array.

dreamlax
yes I know the first element is 0. The code didn't imply it was the first. The second point makes sense, but is that the only advantage? that it returns a mutable array? Why (if the original object is an NSMutableArray) doesn't valueForKey return a mutable one?
lordsandwich
besides, if you write your (NSMutableArray *)array; method in such a way that it returns an NSMutableArray, then the first call will actually get a mutable array, therefore it will be able to use addObject:
lordsandwich
The code says `NSLog (@"first element %@", ...)` and then logs the *second* element.
dreamlax
ok well, the nslog is wrong, but there are actually a bunch of NSStrings in that array
lordsandwich
+3  A: 

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.

Rob Napier
Yay for explaining in detail!
dreamlax
thanks for the answer!
lordsandwich