IOS 高级开发 KVC(二)

  前一篇博客最后介绍了KVC 再json 转模型时遇到一些问题。今天接着来介绍KVC 的其他用法。其实我们在一开始的时候就一直再强调命名的重要性。命名规范是KVC 存活的基础。如果没有这个条件支撑,那么KVC使用起来就不会那么简单了。在这里大王再哔哔几句,作为一个程序员,不管我们长得有多丑,我们的代码一定好看。一段规范的代码代表我们的脸面,也是程序员成熟的标志。既然说到了命名,那么就再来看看KVC 让人吃惊的一面。

1)KVC 方法的搜索顺序

当你看到这个标题的时候,可能会诧异,说的是啥啊?啥是搜索顺序啊?别着急,在介绍调用顺序之前,我们先来看一段很简单的代码,先热身一下。假设我们有一个Person类,这个类是个宅男,头文件中啥玩意都没有。既然头文件中没有任何属性,我们就直接看实现文件。

#import "Person.h"

@interface Person ()

@property(nonatomic,copy)NSString* yourHand;

@end

@implementation Person

-(instancetype)init
{
    self=[super init];
    if (self)
    {
        self.yourHand=@"你的右手";
    }
    return self;
}

-(NSString*)girlFriend
{
    NSLog(@"%s",__func__);
    return self.yourHand;
}

@end

为了防止宅男太过孤单,作为上帝的我,给他创建了手,并在一出生(init)时就给它赋值了。并且创建了一个girlFriend方法。如果我们想调用这个方法直接

[person girlFriend]是不行的(但是我们可以[person performSleector:@selector(girlFriend)],这是因为runtime的关系,这里不详细介绍,可以参看我前几篇博客),在这里,我们还可以这样调用

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    Person *person=[[Person alloc] init];

    NSLog(@"%@",[person valueForKey:@"girlFriend"]);
}

2015-04-27 20:56:37.207 KVC[19591:953199] -[Person girlFriend]

2015-04-27 20:56:37.207 KVC[19591:953199] 你的右手

了解了上面的内容,我们就可以来说说KVC与容器类。什么是容器类呢?说简单点就是数组和集合。这里没啥可说的,还是先看代码吧。还是这个Person类,我们先来稍微改动一下。头文件还是什么都没有,实现文件变为如下

#import "Person.h"

@implementation Person

-(NSUInteger)countOfFingers
{
    return 10;
}

-(id)objectInFingersAtIndex:(NSUInteger)index
{
    NSLog(@"这是第%lu个手指",index);
    return @(index);
}


@end

光看这段代码不神奇,再看一下测试方法和打印信息,我们就会感到很吃惊。

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    Person *person=[[Person alloc] init];

    NSLog(@"%@",[person valueForKey:@"fingers"]);
}

2015-04-27 21:10:53.990 KVC[19658:958083] 这是第0个手指

2015-04-27 21:10:53.991 KVC[19658:958083] 这是第1个手指

2015-04-27 21:10:53.991 KVC[19658:958083] 这是第2个手指

2015-04-27 21:10:53.991 KVC[19658:958083] 这是第3个手指

2015-04-27 21:10:53.991 KVC[19658:958083] 这是第4个手指

2015-04-27 21:10:53.991 KVC[19658:958083] 这是第5个手指

2015-04-27 21:10:53.991 KVC[19658:958083] 这是第6个手指

2015-04-27 21:10:53.992 KVC[19658:958083] 这是第7个手指

2015-04-27 21:10:53.992 KVC[19658:958083] 这是第8个手指

2015-04-27 21:10:53.992 KVC[19658:958083] 这是第9个手指

2015-04-27 21:10:53.992 KVC[19658:958083] (

    0,

    1,

    2,

    3,

    4,

    5,

    6,

    7,

    8,

    9

)

全过程我们都没有直接调用countOfFingers 和-(id)objectInFingersAtIndex:(NSUInteger)index 方法。由打印信息可以知道是系统帮我们调用了。并且有打印信息我们可以知道,系统把fingers 当成属性,并且这个“属性”是数组类型的。当我们调用valueForKey:时,系统会按如下顺序调用方法

 

如果都找不到的话,系统会调用valueForUndefinedKey:方法。以上所讲的都是针对不可变的容器类。如果是可变的容器类,我们可以可以这样使用

dataM= [data mutbaleArrayValueForKey:@"属性"]。当dataM改变的时候,会向data发送消息,data中的内容也会跟着改变。这里我就不详细演示了,有兴趣的可以自己试一下。

2)高阶消息传递

大家可能冷不丁的看到高阶这个词感觉很高大上,仿佛又回到了大学的高数课堂。那么什么是高阶消息传递呢?说白了就是让数组中的每一个元素都执行某个方法,并把结果返回到新的数组中。这下感觉不那么高大上了吧?下面来看一个经典的例子代码

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSArray *array=@[@"烤串",@"啤酒",@"爆米花"];
    NSArray *lengths=[array valueForKeyPath:@"capitalizedString.length"];
    NSLog(@"%@",lengths);
}

2015-04-27 21:53:25.531 KVC[19821:972219] (

    2,

    2,

    3

)

我们可以看出,数组中的每一项都执行了capitalizedString 方法,执行完后,又执行了length 方法。然后把结果返回到新的数组中。在开发中,我们可以适当的使用这个方法,会减少我们的代码量。

  尽管KVC很高大上,但是我们现实开发中,还是谨慎地使用,因为它太过于强大,贸然使用可能会无意间破坏程序的封装性。所以我们只有想清楚了之后再使用,而且最好在使用的地方加上注释。KVC 是大招,我们要在必要的时候使用,动画片里孙悟空也不是在一开始就放大招,你说是不?

posted @ 2015-04-27 22:15  皮拉夫大王  阅读(1135)  评论(3编辑  收藏  举报