直入主题,开头先介绍下本篇学习和探究方向,首先搞清楚成员变量、实例变量、属性的定义,以便KVC赋值取值时能够轻松区分;其次深入探究KVC取值原理、赋值原理;再次通过对YYmodel源码的分析,深入理解KVC;最后再探究一下Category的实现原理及其使用时的注意点。
#import <UIKit/UIKit.h> @interface ViewController : UIViewController //{}内的全部为成员变量,实例变量是一种特殊的成员变量,是由OC中的类声明的成员变量 { UIButton *button; int count; id data; } //GCC --> LLVM 属性 //1.默认的setter + getter //2.自动创建一个带下划线的实例变量匹配属性 @property (nonatomic, strong) UIButton *myButton; @end @implementation ViewController @synthesize myButton = _myButton; //指定与属性对应的实例变量 编译器期间,让编译器自动生成getter/setter方法。 当有自定义的存或取方法时,自定义会屏蔽自动生成该方法 @dynamic myButton; 告诉编译器,不自动生成属性对应的实例变量和访问方法(getter/setter),避免编译期间产生警告; 然后由自己实现存取方法或存取方法在运行时动态创建绑定 @end 复制代码
在{ }中声明的变量都是成员变量;按照上面的例子:button count data都是成员变量;
实例变量本质上就是成员变量,只是实例是针对类而言,实例是指类的声明;
按照上面的例子:button是实例变量 data也是实例变量,因为id是OC特有的类,本质上来说id等同于(void *);
实例变量的英文翻译为 Instance Variable (object-specific storage)
实例的英文翻译为 Instance (manifestation of a class)说的是"类的表现",说明实例变量应该是由类定义的变量!
除去基本数据类型int float ....等,其他类型的变量都叫做实例变量;
属性变量的好处就是允许让其他对象访问到该变量,因为属性创建过程中自动产生了set方法和get方法;当然,你可以设置只读或者可写等,设置方法也可自定义。所以,属性变量是用于与其他对象交互的变量。
键值编码是一种机制,通过NSKeyValueCoding非正式协议,对象采用这种机制提供对其属性的间接访问。当对象符合键值编码时,它的属性可以使用字符串参数通过简明、统一的消息接口进行寻址。这种间接访问机制补充了实例变量及其关联的访问器方法提供的直接访问。 Key-Value Coding Programming Guide 官方文档
set<Key>:
或_set<Key>:
的方法。如果找到, 传入value值并调用。
set<Key>:``_set<Key>:
两个方法,优先调用set<Key>:
方法;
set<Key>:
方法后,就调用了_set<Key>:
方法,证实了KVC的前期赋值情况!
accessInstanceVariablesDirectly
返回YES, 则按以下顺序查找实例变量:_<key>
、_is<Key>
、<key>
、is<Key>
。如果找到, 则直接使用value值设置变量并完成。
_key
赋值;
_key
成员变量注释掉后,就优先给_isKey
赋值,优先级仅次于_key
;
_isKey
注释掉之后,发现给key
赋值;
key
成员变量注释掉之后,最后给isAge赋值,符合了上述setValue:forkey的访问成员变量的优先级 _key > _isKey > key > isKey的顺序。
setValue:forUndefinedKey:
。默认情况下,这会引发异常,但NSObject的子类可以通过重载并根据特定key做一些特殊处理。
get<Key>
、<key>
、is<Key>
或_<key>
的第一个访问器方法。如果找到,调用它并继续到步骤3。否则请继续执行下一步。
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _p = [[YNPerson alloc]init]; NSLog(@"%@",[_p valueForKey:@"name"]); } @end 复制代码
get<Key>
方法;
get<Key>
方法注释掉后,调用了<key>
方法,验证了get<Key>
><key>
;
get<Key>
和<key>
方法注释掉后,调用了is<Key>
方法,验证了get<Key>
> <key>
> is<Key>
;
get<Key>
和<key>
方法以及is<Key>
注释掉后,调用了_<key>
方法,验证了get<Key>
> <key>
> is<Key>
> _<key>
;
accessInstanceVariablesDirectly
返回YES,则系统按以下顺序搜索名为:_<key>
、_is<Key>
、<key>
或is<Key>
的实例变量。如果找到,则直接获取实例变量的值,然后继续执行步骤3。否则, 继续跳转到步骤4。
@interface YNPerson : NSObject { @public NSString *_name; NSString *_isName; NSString *name; NSString *isName; } @end 复制代码
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _p = [[YNPerson alloc]init]; _p->_name = @"_name"; _p->_isName = @"_isName"; _p->name = @"name"; _p->isName = @"isName"; NSLog(@"%@",[_p valueForKey:@"name"]); } @end 复制代码
_<key>
成员变量的值;
_<key>
成员变量时(注释掉成员变量声明和赋值),取_is<Key>
的值;
_<key>
和_is<Key>
成员变量时(注释掉成员变量声明和赋值),取<key>
的值;
_<key>
、_is<Key>
和<key>
成员变量时(注释掉成员变量声明和赋值),取is<Key>
的值;
valueForUndefinedKey:
。默认情况下,这会引发异常,但NSObject的子类可以通过重载并根据特定key做一些特殊处理。
关于此部分内容,请移步至YYModel 原理分析,欢迎查阅、指正。
关于此部分内容,请移步至Category的实现原理及其使用,欢迎查阅、指正。
由于本人水平有限,文中如有不足之处,望大神指出。
如果你看完后觉得对你有所帮助,勿忘点赞
+关注
。
附本文的Demo,赠人玫瑰,手有余香。