iOS-KVC相关

2019-07-28  本文已影响0人  漆黑烈焰武士G

KVC相关


一、 iOS成员变量,实例变量,属性变量的区别

@interface Person : NSObject
{
  @public
    NSString *name;
    id object;  // id是一种特殊的Class,是OC特有的OC对象
    UIButton *btn;// 实例变量--由Class进行实例化而生成的对象为实例变量
    int age;
}// 大括号内均为成员变量
 // 实例变量是一种特殊的成员变量

// 属性 有默认的 setter 和 getter 方法
// 当 LLVM 发现一个属性 没有匹配的  成员变量 时,会生成getter&setter方法并创建一个下划线的成员变量
//  property自动生成的setter和getter方法都会自动生成_<key>的变量,如果只重写setter或getter中的一个,另一个还是会生成下划线变量,但是同时重写setter和getter的话就无法自动生成下划线变量了
@property (nonatomic, copy) NSString *name2;
@property (nonatomic, strong) Son *son;

- (void)walk;
+ (void)study;

@end

二、KVC取值、赋值原理

*学习方式:
1、分析源码 - 没有开源

​ 2、官方文档:Key-Value Coding Programming Guide


KVC是什么

Key-Value是一种通过NSKeyValueCoding协议间接访问成员变量的机制

KVC有什么作用

键值编码

- (void)viewDidLoad
{
  [super viewDidLoad];
  Person *p = [Person new];
  Son *s = [Son new];
  [p setValue:s forKeyPath:@"son"];
  [p setValue:@"hehe" forkey:@"name2"];
  [p setValue:@"didi" forKeyPath:@"son.subject_Son"];
}
KVC的原理是什么
赋值过程 setValue:forKey

1、先查找set<key>,_set<Key>方法,若存在则不走“2、”

2、若没有上述方法且accessInstanceVariablesDirectly==YES,则先存在_<Key>,_is<Key>,<Key>,is<Key>

*上述情况均只执行一次

.h
@interface Person : NSObject{
    @public
    NSString *name; 
    NSString *_name; 
    NSString *_isName;
    NSString *isName;
}

.m
    //此时Person类中没有set<key>,_set<Key>方法
        Person *p = [[Person alloc] init];
    [p setValue:@"hehe" forKey:@"name"];
    
    NSLog(@"p->isName:%@",p->isName);
    NSLog(@"p->name:%@ - p->isName:%@",p->name,p->isName);
    NSLog(@"p->name:%@ - p->isName:%@ - p->_isName:%@",p->name,p->isName,p->_isName);
    NSLog(@"p->name:%@ - p->isName:%@ - p->_name:%@ - p->_isName:%@",
          p->name,p->isName,p->_name,p->_isName);

输出:
 p->isName:(null)
 p->name:(null) - p->isName:(null)
 p->name:(null) - p->isName:(null) - p->_isName:(null)
 p->name:(null) - p->isName:(null) - p->_name:hehe - p->_isName:(null)
取值过程 valueForKey:

1、普通类型

//如果重写了这些方法,则会调用重写的方法,按从上到下的顺序,只调一次
- (NSString *)getName
{
    NSLog(@"%s",__func__);
    return NSStringFromSelector(_cmd);
}
- (NSString *)name
{
    NSLog(@"%s",__func__);
    return NSStringFromSelector(_cmd);
}
- (NSString *)isName
{
    NSLog(@"%s",__func__);
    return NSStringFromSelector(_cmd);
}
- (NSString *)_name
{
    NSLog(@"%s",__func__);
    return NSStringFromSelector(_cmd);
}

2、集合类型:array、set

3、如没有一系列的getter方法,需将accessInstanceVariablesDirectly(是否开启间接访问) 设为为 YES(默认值也是YES)时,访问顺序为:

_<key>,_is<key>,<key>,is<key>

.h  
@interface Person : NSObject{
    @public
    NSString *name; 
    //NSString *_name; 
    NSString *_isName;
    NSString *isName;
}

.m
        Person *p = [[Person alloc] init];
      [p setValue:@"hehe" forKey:@"name"];
    //p->_name   = @"_name";
    p->_isName = @"_isName"; // MAP -- KEY - VALUE
    p->name    = @"name";
    p->isName  = @"isName";
        NSLog(@"%@",[p valueForKey:@"name"]); // 方法 getName
输出:
    //_name
    _isName

*解释:

​ 在赋值时,若set<key>,_set<Key>不存在,但name,_name,_isName,isName都存在,则 [p setValue:@"hehe" forKey:@"name"]实际上是将hehe赋值在_name中,并且不存在其他属性中,若_name不存在则赋值在_isName中。

​ 所以取值时,存的时候存在哪就在哪取,不然取不到。


上一篇下一篇

猜你喜欢

热点阅读