KVC的原理和实现

附csdn demo下载
一 、KVC定义

  • KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过key直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存储方法。这样就可以在运行时动态地访问和修改对象的属性。

  • KVC的定义是对NSObject的扩展实现,OC中有个显式的NSKeyValueCoding类别名,对于所有继承了NSObject的类型都能使用KVC 常用的方法:

    - (nullable id)valueForKey:(NSString *)key;                         //直接通过Key来取值
    - (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来进行设值
    - (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值
    - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值*/
    

二、KVC 设值

KVC要设值,就要对象中有对应的key,KVC的内部是按照怎样的顺序来寻找key的呢,现在我们一起看看底层的机制:

  • 当调用setValue:forKey:时 ,程序会先通过setter(set:)方法,对属性进行设置;
  • 如果没有找到setKey:方法,KVC机制会检查+
    (BOOL)accessInstanceVariablesDirectly方法有没有返回YES
    ,默认该方法是返回YES的,如果重写返回了NO,那么这一步会执行setValue
    forUndefinedKey:方法。若为YES,KVC机制会搜索该类中是否有名为key的成员变量,不管变量在类接口处定义没有,只要存在以key命名的变量,KVC都可以对该成员变量赋值。
  • 如果该类既没有setKey方法,也没有_key成员变量,KVC机制会搜索_isKey的成员变量;如果_isKey成员变量也没有,KVC机制再会继续搜索和is的成员变量给它们赋值,如果上面列出的方法或者成员变量都不存在,系统会执行该对象的setValue:forUndefinedKey:方法
    抛出异常(既 如果没有找到Set方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员并进行赋值操作)

具体的例子体现设值的执行机制:

  1. 正常的 设值和取值

    model 声明

    #import <UIKit/UIKit.h>
    @interface KVCModel : NSObject
    {
        NSString * _title;
    }
    @end
    

    ViewController.m实现

    KVCModel * model = [[KVCModel alloc] init];
    //通过KVC赋值title
    [model setValue:@"标题" forKey:@"title"];
    //通过KVC取值title
    NSLog(@"KVC 获取title值 --- %@",[model valueForKey:@"title"]);
    //上面就是通过- (void)setValue:(nullable id)value forKey:(NSString *)key;和- (nullable id)valueForKey:(NSString *)key;成功设置和取出obj对象的title值。
    

    上面就是通过- (void)setValue:(nullable id)value forKey:(NSString *)key;和- (nullable id)valueForKey:(NSString *)key;成功设置和取出obj对象的title值。

  2. 把accessInstanceVariablesDirectly为NO

    在 KVCModel 重写下面方法

    + (BOOL)accessInstanceVariablesDirectly;
    - (id)valueForUndefinedKey:(NSString *)key ;
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key;
    

    model 实现
    .h

    #import <UIKit/UIKit.h>
    @interface KVCModel : NSObject
    @end
    

    .m

    #import <Foundation/Foundation.h>
    @implementation KVCModel
    
    + (BOOL)accessInstanceVariablesDirectly {
       return NO;
    }
    
    
    - (id)valueForUndefinedKey:(NSString *)key {
        NSLog(@"出现异常,key不存在%@",key);
        return nil;
    }
    
    - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
          NSLog(@"出现异常,key不存在%@", key);
    }
    @end
    

    ViewController.m实现

    KVCModel * model = [[KVCModel alloc] init];
    //通过KVC赋值title
    [model setValue:@"标题2" forKey:@"title"];
    //通过KVC取值title
    NSLog(@"KVC 获取title值 --- %@",[model valueForKey:@"title"]);
    

    运行结果 2018-11-15 15:39:44.936976+0800 KVCDemo[1921:1392533] 出现异常,key不存在title
    2018-11-15 15:39:44.937178+0800 KVCDemo[1921:1392533] 出现异常,key不存在title
    2018-11-15 15:39:44.937263+0800 KVCDemo[1921:1392533] KVC 获取title值 — (null)

    运行发现 accessInstanceVariablesDirectly为NO的时候KVC 只会查询setter和getter这一层,下面寻找key的相关变量执行就会停止,直接报错。

  3. 修改 + (BOOL)accessInstanceVariablesDirectly为YES _title 为 _isTitle
    注意_isTitle 中的is后面的首字母要大写

    model 实现
    .h

    #import <UIKit/UIKit.h>
    
    @interface KVCModel : NSObject
    {
        NSString * _isTitle;
    }
    @end
    

    .m

    #import <Foundation/Foundation.h>
    @implementation KVCModel
    @end
    

    ViewController.m实现

    KVCModel * model = [[KVCModel alloc] init];
    //通过KVC赋值title
    [model setValue:@"标题3" forKey:@"title"];
    //通过KVC取值title
    NSLog(@"KVC 获取title值 --- %@",[model valueForKey:@"title"]);
    

    运行结果:2018-11-15 15:44:50.815772+0800 KVCDemo[1947:1424382] KVC 获取title值 — 标题3

    通过运行结果看到设置accessInstanceVariablesDirectly为YES,当没有_Key属性的时候,KVC会继续按照顺序查找是否有_isKey,并成功设值和取值了。

  4. 修改属性 为 title

    model 实现
    .h

    #import <UIKit/UIKit.h>
    @interface KVCModel : NSObject
    {
        NSString * title;
    }
    @end
    

    .m

    #import <Foundation/Foundation.h>
    @implementation KVCModel
    @end
    

    ViewController.m实现

    KVCModel * model = [[KVCModel alloc] init];
    //通过KVC赋值title
    [model setValue:@"标题4" forKey:@"title"];
    //通过KVC取值title
     NSLog(@"KVC 获取title值 --- %@",[model valueForKey:@"title"]);
    

    运行 2018-11-15 15:46:56.361557+0800 KVCDemo[1969:1438437] KVC 获取title值 — 标题4
    通过运行结果看到设置accessInstanceVariablesDirectly为YES,当没有_Key和_isKey属性的时候,KVC会继续按照顺序查找是否有Key,并成功设值和取值了。

  5. 修改 属性 为 isTitle 注意isTitle 中的is后面的首字母要大写

    model 实现
    .h

    #import <UIKit/UIKit.h>
    @interface KVCModel : NSObject
    {
        NSString * isTitle;
    }
    @end
    

    .m

    #import <Foundation/Foundation.h>
    @implementation KVCModel
    @end
    

    ViewController.m实现

     KVCModel * model = [[KVCModel alloc] init];
     //通过KVC赋值title
     [model setValue:@"标题5" forKey:@"title"];
     //通过KVC取值title
     NSLog(@"KVC 获取title值 --- %@",[model valueForKey:@"title"]);
    

    运行 2018-11-15 15:51:42.996499+0800 KVCDemo[2019:1469259] KVC 获取title值 — 标题5

    通过运行结果看到设置accessInstanceVariablesDirectly为YES,当没有_Key、_isKey和key属性的时候,KVC会继续按照顺序查找是否有isKey,并成功设值和取值了。

  6. 修改 去掉属性

    model 实现
    .h

    #import <UIKit/UIKit.h>
    @interface KVCModel : NSObject
    @end
    

    .m

    #import <Foundation/Foundation.h>
    @implementation KVCModel
    @end
    

    ViewController.m实现

    KVCModel * model = [[KVCModel alloc] init];
    //通过KVC赋值title
    [model setValue:@"标题6" forKey:@"title"];
    //通过KVC取值title
    NSLog(@"KVC 获取title值 --- %@",[model valueForKey:@"title"]);
    

    运行 2018-11-15 15:55:52.128309+0800 KVCDemo[2054:1496609] 出现异常,key不存在title
    2018-11-15 15:55:52.128556+0800 KVCDemo[2054:1496609] 出现异常,key不存在title
    2018-11-15 15:55:52.129384+0800 KVCDemo[2054:1496609] KVC 获取title值 — (null)

    通过运行结果看到设置accessInstanceVariablesDirectly为YES,当没有_Key、_isKey、key、isKey属性的时候,系统将会执行该对象的setValue:forUndefinedKey:方法,默认是抛出异常。
    以上就是 KVC 设值和取值的原来和底层的执行机制

三、KVC取值

KVC 取值 调用valueForKey:时的执行机制

首先会按照getKey,Key,isKey来进行getter方法查找,若存在就赋值;
如果getter方法都没有找到,KVC机制就会查找countOfKey 、objectInKeyAtIndex 、KeyAtindex、getKey :range 这些方法,若上面的几个方法任一个被找到,那么就会返回一个NSKeyValueArray(含有所有的方法的代理集合),以上面的几个方法组合形式调用;

如果上面的countOfKey 、objectInKeyAtIndex 、KeyAtindex、getKey :range 这些方法没有找到 ,会去查找 countOfKey、enumeratorOfKey、memberOfKey格式的方法,若找到这三个方法会返回一个可以相应NSSet所有方法的代理集合,会以countOfKey、enumeratorOfKey、memberOfKey组合形式调用;

如果都没有找到,就去查找+ (BOOL)accessInstanceVariablesDirectly,如果返回YES,就和设值一样的执行机制。
具体的例子体现取值的执行机制:

  • 含有getKey,Key,isKey 方法 注意,这里的key是指成员变量名,首字母大小写要符合KVC的命名规则 ,例如 isTitle
    不然取不到值;

model 实现

.h

#import <UIKit/UIKit.h>
@interface KVCModel : NSObject
@end

.m

#import <Foundation/Foundation.h>
@implementation KVCModel
- (NSString *)title {
    return @"返回title";
}

- (NSString *)isContent {
    return @"返回isContent";
}

- (NSString *)getName {
    return @"返回getName";
}
@end

ViewController.m实现

KVCModel * model = [[KVCModel alloc] init];
NSLog(@"获取KVC值 -- %@  --- %@  --- %@", [model valueForKey:@"title"], [model valueForKey:@"content"], [model valueForKey:@"name"]);
//返回结果 获取KVC值 -- 返回title  --- 返回isContent  --- 返回getName
//可以看出,和上面的执行机制是相同的

四、KVC使用keyPath 除了对当前对象的属性进行赋值外,还可以对其更“深层”的对象进行赋值。例如对当前对象的SubKVCModel属性的title属性进行赋值。KVC进行多级访问时,直接类似于属性调用一样用点语法进行访问即可。
常用方法

 - (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值
 - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值

例子:

创建SubKVCModel 和 KVCModel,给SubKVCModel 添加一个title属性
ViewController代码实现

   SubKVCModel * subModel = [[SubKVCModel alloc] init];
    KVCModel * model = [[KVCModel alloc] init];
    [model setValue:subModel forKey:@"subModel"];
    [model setValue:@"得到title" forKeyPath:@"subModel.title"];
    NSLog(@"keyPath获取到的值:%@",[model valueForKeyPath:@"subModel.title"]);
    运行结果 :2018-11-15 16:55:42.495799+0800 KVCDemo[2214:1756892] keyPath获取到的值:得到title

五、多值操作

KVC还有更强大的功能,可以根据给定的一组key,获取到一组value,并且以字典的形式返回,获取到字典后可以通过key从字典中获取到value。也可以通过KVC进行批量赋值。在对象调用setValuesForKeysWithDictionary:方法时,可以传入一个包含key、value的字典进去,KVC可以将所有数据按照属性名和字典的key进行匹配,并将value给User对象的属性赋值。 常用方法

 - (NSDictionary<nsstring *, id> *)dictionaryWithValuesForKeys:(NSArray<nsstring *> *)keys;</nsstring *></nsstring *, id>
 - (void)setValuesForKeysWithDictionary:(NSDictionary<nsstring *, id> *)keyedValues;</nsstring *, id>

例子 在项目中经常会遇到字典转模型的情况。通过KVC为我们提供的赋值API,可以对数据进行批量赋值。通过setValuesForKeysWithDictionary:方法对User进行赋值。

创建KVCModel模型,定义name、content、subTitle三个属性

NSDictionary * dict = @{@"name":@"name",@"content":@"content",@"subTitle":@"subTitle"};
KVCModel * model = [[KVCModel alloc] init];
[model setValuesForKeysWithDictionary:dict];
NSLog(@"model--> name: %@ content: %@  subTitle: %@",model.name,model.content,model.subTitle);

运行结果 2018-11-15 17:19:16.623203+0800 KVCDemo[2326:1879874] model–> name: name content: content subTitle: subTitle

注意 转换时需要服务器数据和类定义匹配,字段数量和字段名都应该匹配。如果User比服务器数据多,则服务器没传的字段为空。如果服务端传递的数据User中没有定义,则会导致崩溃。 在KVC进行属性赋值时,内部会对基础数据类型做处理,不需要手动做NSNumber的转换。需要注意的是,NSArray和NSDictionary等集合对象,value都不能是nil,否则会导致Crash。

六、KVC处理异常 KVC处理nil异常

当通过KVC给某个非对象的属性赋值为nil时,此时KVC会调用属性所属对象的setNilValueForKey:方法,并抛出NSInvalidArgumentException的异常,并使应用程序Crash。 我们可以通过重写setNilValueForKey:方法

 - (void)setNilValueForKey:(NSString *)key {
     NSLog(@"不能将%@设成nil", key);
 }   

创建NilKVCModel 数据模型 在ViewController中实现下面

NilKVCModel * model = [[NilKVCModel alloc] init];
//通过KVC设值model的name
[model setValue:nil forKey:@"name"];
//通过KVC取值name打印
NSLog(@"名字是%@", [model valueForKey:@"name"]);

运行结果 2018-11-15 17:28:12.956062+0800 KVCDemo[2406:1952070] 名字是(null)

KVC处理UndefinedKey异常

当根据KVC搜索规则,没有搜索到对应的key或者keyPath,则会调用对应的异常方法。异常方法的默认实现,在异常发生时会抛出一个NSUndefinedKeyException的异常,并且应用程序Crash。 可以重写 下面两个方法

 - (nullable id)valueForUndefinedKey:(NSString *)key;
 - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

七、集合运算符
集合运算符主要分为三类:

  • 集合操作符:处理集合包含的对象,并根据操作符的不同返回不同的类型,返回值以NSNumber为主。 简单集合运算符共有@avg,
    @count , @max , @min ,@sum5种

  • 数组操作符:根据操作符的条件,将符合条件的对象包含在数组中返回。 @distinctUnionOfObjects
    @unionOfObjects

  • 嵌套操作符:处理集合对象中嵌套其他集合对象的情况,返回结果也是一个集合对象。 @unionOfArrays
    @distinctUnionOfArrays

    1、 简单集合运算符

    例子 给SubKVCModel 添加age属性

    SubKVCModel * model = [[SubKVCModel alloc] init];
    model.age = 12;
    SubKVCModel * model1 = [[SubKVCModel alloc] init];
    model1.age = 13;
    SubKVCModel * model2 = [[SubKVCModel alloc] init];
    model2.age = 14;
    SubKVCModel * model3 = [[SubKVCModel alloc] init];
    model3.age = 15;
    SubKVCModel * model4 = [[SubKVCModel alloc] init];
    model4.age = 16;
    NSArray * arr = @[model,model1,model2,model3,model4];
    NSNumber* sum = [arr valueForKeyPath:@"@sum.age"];
    NSLog(@"sum:%f",sum.floatValue);
    NSNumber* avg = [arr valueForKeyPath:@"@avg.age"];
    NSLog(@"avg:%f",avg.floatValue);
    NSNumber* count = [arr valueForKeyPath:@"@count"];
    NSLog(@"count:%f",count.floatValue);
    NSNumber* min = [arr valueForKeyPath:@"@min.age"];
    NSLog(@"min:%f",min.floatValue);
    NSNumber* max = [arr valueForKeyPath:@"@max.age"];
    NSLog(@"max:%f",max.floatValue);
    

    运行结果:
    2018-11-16 10:02:51.964400+0800 KVCDemo[3222:2547677] sum:70.000000
    2018-11-16 10:02:51.964704+0800 KVCDemo[3222:2547677] avg:14.000000
    2018-11-16 10:02:51.964848+0800 KVCDemo[3222:2547677] count:5.000000
    2018-11-16 10:02:51.965055+0800 KVCDemo[3222:2547677] min:12.000000
    2018-11-16 10:02:51.965163+0800 KVCDemo[3222:2547677] max:16.000000

    @max用来查找集合中right keyPath指定的属性的最大值。
    @sum用来计算集合中right keyPath指定的属性的总和。
    @min用来查找集合中right keyPath指定的属性的最小值。
    @count用来计算集合的总数。
    @avg用来计算集合中right keyPath指定的属性的平均值。
    注意:@count操作符比较特殊,它不需要写right keyPath,即使写了也会被忽略。
    @max和@min在进行判断时,都是通过调用compare:方法进行判断,所以可以通过重写该方法对判断过程进行控制。

    2、数组操作符
    例子
    给SubKVCModel 添加age属性和name属性

    SubKVCModel * model = [[SubKVCModel alloc] init];
    model.age = 12;
    model.name = @"小明";
    SubKVCModel * model1 = [[SubKVCModel alloc] init];
    model1.age = 13;
    model1.name = @"小方";
    SubKVCModel * model2 = [[SubKVCModel alloc] init];
    model2.age = 14;
    model2.name = @"小涛";
    
    SubKVCModel * model3 = [[SubKVCModel alloc] init];
    model3.age = 15;
    model3.name = @"小童";
    
    SubKVCModel * model4 = [[SubKVCModel alloc] init];
    model4.age = 16;
    model4.name = @"小超";
    NSArray * arr = @[model,model1,model2,model3,model4];
    
    NSArray* arrDistinct = [arr valueForKeyPath:@"@distinctUnionOfObjects.age"];
    for (NSNumber *age in arrDistinct) {
        NSLog(@"distinctUnionOfObjects -%f",age.floatValue);
    }
    //@distinctUnionOfObjects将集合对象中,所有age对象放在一个数组中,并将数组进行去重后返回。
    NSArray* arrUnion = [arr valueForKeyPath:@"@unionOfObjects.age"];
    for (NSNumber * age in arrUnion) {
        NSLog(@"unionOfObjects - %f",age.floatValue);
    }
    //@unionOfObjects将集合对象中,所有age对象放在一个数组中并返回。
    

    运行结果:
    2018-11-16 10:08:54.253126+0800 KVCDemo[3266:2595522] distinctUnionOfObjects -14.000000
    2018-11-16 10:08:54.253241+0800 KVCDemo[3266:2595522] distinctUnionOfObjects -13.000000
    2018-11-16 10:08:54.253331+0800 KVCDemo[3266:2595522] distinctUnionOfObjects -16.000000
    2018-11-16 10:08:54.253401+0800 KVCDemo[3266:2595522] distinctUnionOfObjects -12.000000
    2018-11-16 10:08:54.253596+0800 KVCDemo[3266:2595522] distinctUnionOfObjects -15.000000
    2018-11-16 10:08:54.253734+0800 KVCDemo[3266:2595522] unionOfObjects - 12.000000
    2018-11-16 10:08:54.253820+0800 KVCDemo[3266:2595522] unionOfObjects - 13.000000
    2018-11-16 10:08:54.253954+0800 KVCDemo[3266:2595522] unionOfObjects - 14.000000
    2018-11-16 10:08:54.254022+0800 KVCDemo[3266:2595522] unionOfObjects - 15.000000
    2018-11-16 10:08:54.254127+0800 KVCDemo[3266:2595522] unionOfObjects - 16.000000

    3、嵌套操作符 @unionOfArrays @distinctUnionOfArrays @distinctUnionOfSets
    例子 给SubKVCModel 添加age属性和name属性

     SubKVCModel * model = [[SubKVCModel alloc] init];
     model.age = 12;
     model.name = @"小明";
     SubKVCModel * model1 = [[SubKVCModel alloc] init];
     model1.age = 13;
     model1.name = @"小方";
     SubKVCModel * model2 = [[SubKVCModel alloc] init];
     model2.age = 14;
     model2.name = @"小涛";
     SubKVCModel * model3 = [[SubKVCModel alloc] init];
     model3.age = 15;
     model3.name = @"小童";
     SubKVCModel * model4 = [[SubKVCModel alloc] init];
     model4.age = 16;
     model4.name = @"小超";
     NSArray * arr = @[model,model1,model2,model3,model4];
     NSArray * arr1 = @[model,model1,model2,model3,model4];
     NSArray * array = @[arr,arr1];
     NSArray * unionOfArray = [array valueForKeyPath:@"@unionOfArrays.age"];
     NSLog(@"%@",unionOfArray);
     NSArray * distinctUnionOfArray = [array valueForKeyPath:@"@distinctUnionOfArrays.age"];
     NSLog(@"%@",distinctUnionOfArray);
    

    运行结果:

    2018-11-16 10:38:10.458312+0800 KVCDemo[3483:2785420] (
    12,
    13,
    14,
    15,
    16,
    12,
    13,
    14,
    15,
    16
    )
    2018-11-16 10:38:10.458601+0800 KVCDemo[3483:2785420] (
    13,
    14,
    15,
    16,
    12
    )

    @unionOfArrays是用来操作集合内部的集合对象,将所有right keyPath对应的对象放在一个数组中返回。
    @distinctUnionOfArrays是用来操作集合内部的集合对象,将所有right keyPath对应的对象放在一个数组中,并进行排重。

八 、属性验证

在调用KVC时可以先进行验证,验证通过下面两个方法进行,支持key和keyPath两种方式。验证方法默认实现返回YES,可以通过重写对应的方法修改验证逻辑。
验证方法需要我们手动调用,并不会在进行KVC的过程中自动调用。

 - (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
 - (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;

九、总结: KVC使用

 1、动态地取值和设值
 利用KVC动态的取值和设值。
 
 2、用KVC来访问和修改私有变量
 对于类里的私有属性,Objective-C是无法直接访问的,但是KVC是可以的。  KVC本质上是操作方法列表以及在内存中查找实例变量。我们可以利用这个特性访问类的私有变量,例如下面在.m中定义的私有成员变量和属性,都可以通过KVC的方式访问。
 这个操作对readonly的属性,@protected的成员变量,都可以正常访问。如果不想让外界访问类的成员变量,则可以将accessInstanceVariablesDirectly属性赋值为NO。

3、 Model和字典转换
 这是KVC强大作用的又一次体现,KVC和Objc的runtime组合可以很容易的实现Model和字典的转换。
 
4、 修改一些控件的内部属性
 这也是iOS开发中必不可少的小技巧。众所周知很多UI控件都由很多内部UI控件组合而成的,但是Apple度没有提供这访问这些控件的API,这样我们就无法正常地访问和修改这些控件的样式。
 而KVC在大多数情况可下可以解决这个问题。最常用的就是个性化UITextField中的placeHolderText了。

5、 操作集合
Apple对KVC的valueForKey:方法作了一些特殊的实现,比如说NSArray和NSSet这样的容器类就实现了这些方法。所以可以用KVC很方便地操作集合。

注意:KVC是支持基础数据类型和结构体的,可以在setter和getter的时候,通过NSValue和NSNumber来转换为OC对象。Swift中不存在这样的需求,因为Swift中所有变量都是对象。
需要注意的是,无论什么时候都不应该给setter中传入nil,会导致Crash并引起NSInvalidArgumentException异常。
尽管valueForKey:会自动将值类型封装成对象,但是setValue:forKey:却不行。你必须手动将值类型转换成NSNumber或者NSValue类型,才能传递过去。 因为传递进去和取出来的都是id类型,所以需要开发者自己担保类型的正确性,运行时Objective-C在发送消息的会检查类型,如果错误会直接抛出异常。
KVC存在一个问题在于,因为传入的key或keyPath是一个字符串,这样很容易写错或者属性自身修改后字符串忘记修改,这样会导致Crash。
可以利用iOS的反射机制来规避这个问题,通过@selector()获取到方法的SEL,然后通过NSStringFromSelector()将SEL反射为字符串。这样在@selector()中传入方法名的过程中,编译器会有合法性检查,如果方法不存在或未实现会报黄色警告。
[self valueForKey:NSStringFromSelector(@selector(object))];

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值