KVC 原理及自定义实现
一. setValue: forKey: 赋值过程
1.首先寻找setter方法(两个)
- setName:
-setIsName:
2.然后再寻找成员变量
默认 + (BOOL)accessInstanceVariablesDirectly 返回YES;
_key > _isKey > key > isKey
3. 如果以上步骤没有找到key,则会报异常; 也可以重写方法,防止崩溃
-setValue: forUndefinedKey:
二. valueForKey: 取值过程
1.getter方法(三个)
-getKey
-key
-isKey
2.成员变量
_key > _isKey > key > isKey
3.上述没有,可重写,防止崩溃
-valueForUndefinedKey
三. runtime 简单实现 KVC
新建一个NSObject 一个分类
#import "NSObject+kvc.h"
#import <objc/runtime.h>
@implementation NSObject (kvc)
- (void)xs_setValue:(id)value forKey:(NSString *)key{
//key 需要合法
if (key == nil || key.length == ) {
return;
}
//一.setter 方法
//调用相关setter方法(capitalizedString 首字母大写)
NSString *setKey = [NSString stringWithFormat:@"set%@:",[key capitalizedString]];
//调用
if ([self respondsToSelector:NSSelectorFromString(setKey)]) {
[self performSelector:NSSelectorFromString(setKey) withObject:value];
return;
}
NSString *setIsKey = [NSString stringWithFormat:@"setIs%@:",[key capitalizedString]];
if ([self respondsToSelector:NSSelectorFromString(setIsKey)]) {
[self performSelector:NSSelectorFromString(setIsKey) withObject:value];
return;
} //异常处理方法
if (![self.class accessInstanceVariablesDirectly]) {
NSException *exception = [NSException exceptionWithName:@"XSKVC Exception" reason:@"你返回了NO啊!" userInfo:nil];
@throw exception;
return;
}
//二.成员变量
unsigned int count = ;
//获取所有成员变量
Ivar *ivars = class_copyIvarList([self class], &count);//解释:在C中,copy new create 在堆区开辟内存空间
// NSMutableArray *array = [NSMutableArray array];
// for (int i = 0; i<count; i++) {
// Ivar ivar = ivars[i];
// const char *name = ivar_getName(ivar);
// NSString *keyName = [NSString stringWithUTF8String:name];
// [array addObject:keyName];
// }
//_key (按照优先级:_key > _isKey > key > isKey)
for (int i = ; i<count; i++) {
Ivar ivar = ivars[i];
NSString *keyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
if ([keyName isEqualToString:[NSString stringWithFormat:@"_%@",key]]) {
object_setIvar(self, ivar, value);
free(ivars);
return;
}
}
//_isKey
for (int i = ; i<count; i++) {
Ivar ivar = ivars[i];
NSString *keyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
if ([keyName isEqualToString:[NSString stringWithFormat:@"_is%@",key.capitalizedString]]) {
object_setIvar(self, ivar, value);
free(ivars);
return;
}
}
//key
for (int i = ; i<count; i++) {
Ivar ivar = ivars[i];
NSString *keyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
if ([keyName isEqualToString:[NSString stringWithFormat:@"%@",key]]) {
object_setIvar(self, ivar, value);
free(ivars);
return;
}
}
//isKey
for (int i = ; i<count; i++) {
Ivar ivar = ivars[i];
NSString *keyName = [NSString stringWithUTF8String:ivar_getName(ivar)];
if ([keyName isEqualToString:[NSString stringWithFormat:@"is%@",key.capitalizedString]]) {
object_setIvar(self, ivar, value);
free(ivars);
return;
}
} //处理异常
[self setValue:value forUndefinedKey:key];
free(ivars); }
KVC 原理及自定义实现的更多相关文章
- 【原】iOS学习之KVC原理
1. KVC的实现原理 遍历字典里面所有的key,以name为例 去模型中查找有没有setName:方法,有就直接调用赋值 假如没有找到setName:方法,就会继续查找有没有_name属性,有就_n ...
- JAVA之旅(二十五)——文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine
JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇 ...
- Spring MVC内容协商实现原理及自定义配置【享学Spring MVC】
每篇一句 在绝对力量面前,一切技巧都是浮云 前言 上文 介绍了Http内容协商的一些概念,以及Spring MVC内置的4种协商方式使用介绍.本文主要针对Spring MVC内容协商方式:从步骤.原理 ...
- 【SpringBoot1.x】SpringBoot1.x 启动配置原理 和 自定义starter
SpringBoot1.x 启动配置原理 和 自定义starter 启动配置原理 本节源码 启动过程主要为: new SpringApplication(sources) 创建 SpringAppli ...
- WPF打印原理,自定义打印
一.基础知识 1.System.Printing命名空间 我们可以先看一下System.Printing命名空间,东西其实很多,功能也非常强大,可以说能够控制打印的每一个细节,曾经对PrintDial ...
- 深入了解View实现原理以及自定义View详解
下面几篇文章对View的原理讲的非常详细. Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了解View(二) ...
- (转)浅谈dedecms模板引擎工作原理及自定义标签
理解织梦模板引擎有什么意义?一方面可以更好地自定义标签.更多在于了解织梦系统,理解模板引擎是理解织梦工作原理的第一步.理解织梦会使我们写php代码时更顺手,同时能学习一些php代码的组织方式. 这似乎 ...
- 贝塞尔曲线:原理、自定义贝塞尔曲线View、使用!!!
一.原理 转自:http://www.2cto.com/kf/201401/275838.html Android动画学习Demo(3) 沿着贝塞尔曲线移动的Property Animation Pr ...
- SpringBoot之旅第六篇-启动原理及自定义starter
一.引言 SpringBoot的一大优势就是Starter,由于SpringBoot有很多开箱即用的Starter依赖,使得我们开发变得简单,我们不需要过多的关注框架的配置. 在日常开发中,我们也会自 ...
随机推荐
- adf错误
1>无法验证事务处理中的所有行 运行项目报错: javax.faces.el.EvaluationException: oracle.jbo.TxnValException: JBO-27023 ...
- Windows查看端口占用及杀掉进程
"到底是谁占用了80端口,该怎么查,怎么终止它?",这里就简单讲解一下,在windows下如何查看80端口占用情况?是被哪个进程占用?如何终止等.这里主要是用到windows下的D ...
- noi2729 Blah数集
Blah数集 大数学家高斯小时候偶然间发现一种有趣的自然数集合Blah,对于以a为基的集合Ba定义如下: (1) a是集合Ba的基,且a是Ba的第一个元素: (2)如果x在集合Ba中,则2x+1和3x ...
- SQL基础问题(一)
1.sql是什么? 结构化查询语言(Structured Query Language). 2.结构化查询语言的分类? 数据定义语言(DDL)Data Definition Language 操作 ...
- cakephp绑定事件
<input type='button' id="submitBtn" class="col button button-fill " value='确认 ...
- http post 方法传递参数的2种方式
1.StringEntity try{ HttpPost httpPost = new HttpPost(url); //param参数,可以为param="key1=value1&a ...
- 选项“6”对 /langversion 无效;必须是 ISO-1、ISO-2、3、4、5 或 Default
部署MVC的时候,因为服务器.NET版本是4.5.1,所以在vs将.NET版本降到4.5.1的时候发布报错. 原因:C#6降到C#5导致 解决办法:修改web.config配置 ,编译选项改为comp ...
- bootstrap-海棠
12 缩略图和警告框 <p class='alert alert-info'>这个是警告组<button class='close' data-dismiss='alert'> ...
- CentOS 7搭建FTP服务器
安装vsftpd 命令:yum -y install vsftpd 修改ftp配置文件 命令:vim /etc/vsftpd/vsftpd.conf 按i进入insert模式后,按以下要求修改 ano ...
- 版本控制-https svn服务器搭建和常用命令(centos 6.3)
Svn是比较优秀的版本控制工具,虽然功能和性能上无法和Git媲美,但由于其容易搭建和使用的特性,所以在各个小公司还是很受欢迎的.使用Git可参考<版本控制-Git服务器搭建和常用命令使用> ...