直入主题,开头先介绍下本篇学习和探究方向,首先搞清楚成员变量、实例变量、属性的定义,以便KVC赋值取值时可以轻松区分;其次深刻探究KVC取值原理、赋值原理;再次经过对YYmodel源码的分析,深刻理解KVC;最后再探究一下Category的实现原理及其使用时的注意点。html
#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都是成员变量;ios
实例变量本质上就是成员变量,只是实例是针对类而言,实例是指类的声明;git
按照上面的例子:button是实例变量 data也是实例变量,由于id是OC特有的类,本质上来讲id等同于(void *);bash
实例变量的英文翻译为 Instance Variable (object-specific storage)app
实例的英文翻译为 Instance (manifestation of a class)说的是"类的表现",说明实例变量应该是由类定义的变量!ide
除去基本数据类型int float ....等,其余类型的变量都叫作实例变量;学习
属性变量的好处就是容许让其余对象访问到该变量,由于属性建立过程当中自动产生了set方法和get方法;固然,你能够设置只读或者可写等,设置方法也可自定义。因此,属性变量是用于与其余对象交互的变量。ui
键值编码是一种机制,经过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 原理分析,欢迎查阅、指正。atom
关于此部份内容,请移步至Category的实现原理及其使用,欢迎查阅、指正。
因为本人水平有限,文中若有不足之处,望大神指出。
若是你看完后以为对你有所帮助,勿忘点赞
+关注
。
附本文的Demo,赠人玫瑰,手有余香。