我准备了一个用于测试的类Person
。
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
我通过KVC的方式为name
赋值和取值。
Person *person = [[Person alloc] init];
[person setValue:@"a" forKey:@"name"];
NSLog(@"%@", [person valueForKey:@"name"]);
// result: a
接下来,我对NSArray
进行KVC操作。
Person *p1 = [[Person alloc] init];
p1.name = @"a";
p1.age = 10;
Person *p2 = [[Person alloc] init];
p2.name = @"b";
p2.age = 15;
NSArray *array = @[p1, p2];
id result = [array valueForKey:@"name"];
NSLog(@"%@", result);
这是什么操作?NSArray
并没有name
这个属性,结果肯定是valueForUndefinedKey:
。
看看真实的结果是什么。
(
a,
b
)
结果是一个数组?对,就是一个数组。仔细观察看看,p1.name
== a
,p2.name
== b
。
为什么呢?
来看看源码吧。
- (id) valueForKey: (NSString*)key
{
id result = nil;
if ([key isEqualToString: @"@count"] == YES)
{
result = [NSNumber numberWithUnsignedInteger: [self count]];
}
else if ([key isEqualToString: @"count"] == YES)
{
GSOnceMLog(
@"[NSArray-valueForKey:] called with 'count' is deprecated .. use '@count'");
result = [NSNumber numberWithUnsignedInteger: [self count]];
}
else
{
NSMutableArray *results = nil;
static NSNull *null = nil;
NSUInteger i;
NSUInteger count = [self count];
volatile id object = nil;
results = [NSMutableArray arrayWithCapacity: count];
for (i = 0; i < count; i++)
{
id result;
object = [self objectAtIndex: i];
result = [object valueForKey: key];
if (result == nil)
{
if (null == nil)
{
null = RETAIN([NSNull null]);
}
result = null;
}
[results addObject: result];
}
result = results;
}
return result;
}
再来看看setValue:forKey:
。
- (void) setValue: (id)value forKey: (NSString*)key
{
NSUInteger i;
NSUInteger count = [self count];
volatile id object = nil;
for (i = 0; i < count; i++)
{
object = [self objectAtIndex: i];
[object setValue: value
forKey: key];
}
}
还有valueForKeyPath:
。
- (id) valueForKeyPath: (NSString*)path
{
id result = nil;
if ([path hasPrefix: @"@"])
{
NSRange r;
r = [path rangeOfString: @"."];
if (r.length == 0)
{
if ([path isEqualToString: @"@count"] == YES)
{
result = [NSNumber numberWithUnsignedInteger: [self count]];
}
else
{
result = [self valueForKey: path];
}
}
else
{
NSString *op = [path substringToIndex: r.location];
NSString *rem = [path substringFromIndex: NSMaxRange(r)];
NSUInteger count = [self count];
if ([op isEqualToString: @"@count"] == YES)
{
result = [NSNumber numberWithUnsignedInteger: count];
}
else if ([op isEqualToString: @"@avg"] == YES)
{
double d = 0;
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
while ((o = [e nextObject]) != nil)
{
d += [[o valueForKeyPath: rem] doubleValue];
}
d /= count;
}
result = [NSNumber numberWithDouble: d];
}
else if ([op isEqualToString: @"@max"] == YES)
{
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
while ((o = [e nextObject]) != nil)
{
o = [o valueForKeyPath: rem];
if (result == nil
|| [result compare: o] == NSOrderedAscending)
{
result = o;
}
}
}
}
else if ([op isEqualToString: @"@min"] == YES)
{
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
while ((o = [e nextObject]) != nil)
{
o = [o valueForKeyPath: rem];
if (result == nil
|| [result compare: o] == NSOrderedDescending)
{
result = o;
}
}
}
}
else if ([op isEqualToString: @"@sum"] == YES)
{
double d = 0;
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
while ((o = [e nextObject]) != nil)
{
d += [[o valueForKeyPath: rem] doubleValue];
}
}
result = [NSNumber numberWithDouble: d];
}
else if ([op isEqualToString: @"@distinctUnionOfArrays"] == YES)
{
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
result = [NSMutableSet set];
while ((o = [e nextObject]) != nil)
{
o = [o valueForKeyPath: rem];
[result addObjectsFromArray: o];
}
result = [result allObjects];
}
else
{
result = [NSArray array];
}
}
else if ([op isEqualToString: @"@distinctUnionOfObjects"] == YES)
{
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
result = [NSMutableSet set];
while ((o = [e nextObject]) != nil)
{
o = [o valueForKeyPath: rem];
[result addObject: o];
}
result = [result allObjects];
}
else
{
result = [NSArray array];
}
}
else if ([op isEqualToString: @"@distinctUnionOfSets"] == YES)
{
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
result = [NSMutableSet set];
while ((o = [e nextObject]) != nil)
{
o = [o valueForKeyPath: rem];
[result addObjectsFromArray: [o allObjects]];
}
result = [result allObjects];
}
else
{
result = [NSArray array];
}
}
else if ([op isEqualToString: @"@unionOfArrays"] == YES)
{
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
result = [GSMutableArray array];
while ((o = [e nextObject]) != nil)
{
o = [o valueForKeyPath: rem];
[result addObjectsFromArray: o];
}
result = GS_IMMUTABLE(result);
}
else
{
result = [NSArray array];
}
}
else if ([op isEqualToString: @"@unionOfObjects"] == YES)
{
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
result = [GSMutableArray array];
while ((o = [e nextObject]) != nil)
{
o = [o valueForKeyPath: rem];
[result addObject: o];
}
result = GS_IMMUTABLE(result);
}
else
{
result = [NSArray array];
}
}
else if ([op isEqualToString: @"@unionOfSets"] == YES)
{
if (count > 0)
{
NSEnumerator *e = [self objectEnumerator];
id o;
result = [GSMutableArray array];
while ((o = [e nextObject]) != nil)
{
o = [o valueForKeyPath: rem];
[result addObjectsFromArray: [o allObjects]];
}
result = GS_IMMUTABLE(result);
}
else
{
result = [NSArray array];
}
}
else
{
result = [super valueForKeyPath: path];
}
}
}
else
{
result = [super valueForKeyPath: path];
}
return result;
}
网友评论