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依赖,使得我们开发变得简单,我们不需要过多的关注框架的配置. 在日常开发中,我们也会自 ...
随机推荐
- PollingProvider方法的使用及示例
来自<sencha touch权威指南>第12章,374页开始 ----------------------------------------------------- PollingP ...
- Python爬虫入门二之爬虫基础了解
1.什么是爬虫 爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛咯,如果它遇到资源,那么它就会抓取下来.想抓取什么?这个由你来控制它咯. ...
- [SoapUI] 按照 Test Step Type 获取所有满足条件的 Test Step
获取当前测试用例下所有Groovy Script类型的测试步骤 def testStepList = testRunner.testCase.getTestStepsOfType(com.eviwar ...
- 【转载】java实现rabbitmq消息的发送接受
原文地址:http://blog.csdn.net/sdyy321/article/details/9241445 本文不介绍amqp和rabbitmq相关知识,请自行网上查阅 本文是基于spring ...
- 【转载】如何选择MySQL存储引擎
一.MySQL的存储引擎 完整的引擎说明还是看官方文档:http://dev.mysql.com/doc/refman/5.6/en/storage-engines.html 这里介绍一些主要的引擎 ...
- JW Player开始播放和结束播放事件的捕获
项目中使用到jwPlayer,需要在用户开始播放盒结束播放的时候触发一些事件,所以研究JWPlayer. <script type="text/javascript"> ...
- HashMap的小试牛刀
HashMap的介绍 import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.ut ...
- 使用web API和NPOI导出Excel
使用MVC controller输出excel的例子,自不待言,例子满天飞. 由于本项目使用的是Asp.net MVC API,因此在本项目使用API,实现了文件下载功能.代码的原理很简单,基本上是老 ...
- 解决 centos 7 部署 tomcat 后外部不能访问应用(端口、防火墙)
https://blog.csdn.net/Rebs_Hugo/article/details/85042602
- django drf Filter
1.定义get_queryset()方法 from django.shortcuts import render from rest_framework.views import APIView fr ...