zoukankan      html  css  js  c++  java
  • KVC

    KVC的使用

    1、KVC 全称 key valued coding 键值编码 

    反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性.JAVA,C#都有这个机制。ObjC也有,所以你根部不必进行任何操作就可以进行属性的动态读写,就是KVC。

    KVC的操作方法由NSKeyValueCoding提供,而他是NSObject的类别,也就是说ObjC中几乎所有的对象都支持KVC操作。

    2、常用方法

    获取值的方法

    valueForKey:,传入NSString属性的名字。

    valueForKeyPath:,传入NSString属性的路径,xx.xx形式。

    valueForUndefinedKey它的默认实现是抛出异常,可以重写这个函数做错误处理。

    修改值的方法

    setValue:forKey:

    setValue:forKeyPath:

    setValue:forUndefinedKey:

    Person.h

    Person.m

    main

     setValue:forKey的搜索过程:

    1. 首先搜索set<Key>:方法

    如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的setter方法,所以这种情况下会直接搜索到。

    注意:这里的<Key>是指成员名,而且首字母大写。

    2. 上面的setter方法没有找到,如果类方法accessInstanceVariablesDirectly返回YES(注:这是NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)。

    那么按_<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。

    3. 如果还是没有找到设置成员的值,就会调用setValue:forUndefinedKey:。

    4. 如果没有重写setValue:forUndefinedKey程序会马上崩溃。

    注意:

    1、使用KVC间接修改对象属性时,系统会自动判断对象属性的类型,并完成转换。.

    2、KVC可以访问成员变量,无论是否提供getter/setter方法,无论可见性是怎样,是否有readonly修饰。

    setValue:forUndefinedKey与valueForUndefinedKey的应用

    KVC的主要用途无非是ORM映射,就是将dictionary转换成model,但有些服务器返回的字段有可能是oc的关键字比如‘id’,’description’等。如上代码举得id的例子,我们无法让@property后面key值为id,于是使用大写的ID代替,KVC是区分大小写的我们不用担心。这时我们只需在setValue:forUndefinedKey把id的key值赋值给ID的key值,就可以避免关键字的尴尬。

    KVC的逆向使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Person * p1 = [[Person alloc]init];
    [p1 setValue:@"170" forKey:@"height"];
    [p1 setValue:@"70" forKey:@"weight"];
    [p1 setValue:@"11111" forKey:@"id"];


    NSArray * arr = @[@"height",@"weight",@"id"];
    NSDictionary * dict = [p1 dictionaryWithValuesForKeys:arr];
    NSLog(@"%@",dict);

    log日志:
    {
    height = 170;
    id = 11111;
    weight = 70;
    }

    NSArray/NSSet等都支持KVC

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    Person * p1 = [[Person alloc]init];
    Dog * d1 = [[Dog alloc] init];
    d1.name = @"iPhone";
    p1.dog = d1;

    Person * p2 = [[Person alloc]init];
    Dog * d2 = [[Dog alloc] init];
    d2.name = @"ios";
    p2.dog = d2;

    NSArray *persons=@[p1,p2];

    NSArray *arrayM=[persons valueForKeyPath:@"dog.name"];
    NSLog(@"%@",arrayM);

    log日志:
    (
    iPhone,
    ios
    )

    KVC计算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    Person * person = [[Person alloc] init];

    NSMutableArray * books = [NSMutableArray array];
    for (int i = 0; i < 10; i++) {
    Book * book = [[Book alloc] init];
    book.price = i;
    [books addObject:book];
    }

    person.books = books;

    NSNumber *bookCount = [person valueForKeyPath:@"books.@count"];
    NSLog(@"book count :%@", bookCount);

    NSNumber *sum = [person valueForKeyPath:@"books.@sum.price"];
    NSLog(@"sum :%@", sum);

    NSNumber *avg = [person valueForKeyPath:@"books.@avg.price"];
    NSLog(@"vag :%@", avg);

    NSNumber *min = [person valueForKeyPath:@"books.@min.price"];
    NSLog(@"min :%@", min);

    NSNumber *max = [person valueForKeyPath:@"books.@max.price"];
    NSLog(@"max :%@", max);

    KVC底层实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    比如说如下的一行KVC的代码:

    [person setValue:@"dahuan" forKey:@"name"];

    就会被编译器处理成:

    SEL sel = sel_get_uid ("setValue:forKey:");
    IMP method = objc_msg_lookup (person->isa,sel);
    method(person, sel, @"dahuan", @"name");

    KVC与runtime应用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    #import "MyModel.h"
    #import <objc/runtime.h>

    @implementation MyModel

    //解档
    - (id)initWithCoder:(NSCoder *)decoder
    {
    if (self = [super init]) {
    unsigned int count = 0;
    //获取类中所有成员变量名
    Ivar *ivar = class_copyIvarList([MyModel class], &count);
    for (int i = 0; i<count; i++) {
    Ivar iva = ivar[i];
    const char *name = ivar_getName(iva);
    NSString *strName = [NSString stringWithUTF8String:name];
    //进行解档取值
    id value = [decoder decodeObjectForKey:strName];
    //利用KVC对属性赋值
    [self setValue:value forKey:strName];
    }
    free(ivar);
    }
    return self;
    }

    //归档
    - (void)encodeWithCoder:(NSCoder *)encoder
    {
    unsigned int count;
    Ivar *ivar = class_copyIvarList([MyModel class], &count);
    for (int i=0; i<count; i++) {
    Ivar iv = ivar[i];
    const char *name = ivar_getName(iv);
    NSString *strName = [NSString stringWithUTF8String:name];
    //利用KVC取值
    id value = [self valueForKey:strName];
    [encoder encodeObject:value forKey:strName];
    }
    free(ivar);
    }
    @end
  • 相关阅读:
    云原生时代,微服务到底应该怎么玩儿?
    坐上机器猫的时光机,来一场科技穿越之旅吧
    喜讯|京东荣获2019 【中国技术品牌影响力企业】
    非洲正在打造一个与硅谷完全不同的人工智能产业
    DevOps专题|基础Agent部署系统
    《编写可读代码的艺术》总结
    《Effective Java第二版》总结
    MySQL之备份和还原
    MySQL之Xtrabackup的使用
    MySQL之mysqldump的使用
  • 原文地址:https://www.cnblogs.com/ycg0808/p/5322378.html
Copyright © 2011-2022 走看看