美文网首页OC Tips
NSArray-不一样的KVC

NSArray-不一样的KVC

作者: 旭宝爱吃鱼 | 来源:发表于2020-03-19 14:00 被阅读0次

    我准备了一个用于测试的类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 == ap2.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;
    }
    

    相关文章

      网友评论

        本文标题:NSArray-不一样的KVC

        本文链接:https://www.haomeiwen.com/subject/tfxlyhtx.html