正文
福利->KVC+Runtime获取类/对象的属性/成员变量/方法/协议并实现字典转模型
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
我们知道,KVC+Runtime可以做非常多的事情。有了这个,我们可以实现很多的效果。
这里来个福利,利用KVC+Runtime获取类/对象的所有成员变量、属性、方法及协议;
并利用它来实现字典转模型。
废话不多说,直接上代码:
1、工具类(其实就是NSObject的一个分类)头文件
#import <Foundation/Foundation.h> @interface NSObject (YSRuntime) /**
返回当前类的属性数组 @return 属性数组(如:"name","age","address")
*/
+ (NSArray *)ys_propertiesList; /**
返回当前类的成员变量数组 @return 成员变量数组
*/
+ (NSArray *)ys_ivarsList; /**
返回当前类的对象方法数组 @return 方法数组
*/
+ (NSArray *)ys_methodList; /**
返回当前类的协议数组 @return 协议数组
*/
+ (NSArray *)ys_protocolList; /**
使用字典创建当前类的对象 @param dictionary 字典 @return 当前类的对象
*/
+ (instancetype)ys_objectWithDictionary:(NSDictionary *)dictionary; /**
使用字典数组创建当前类的对象数组 @param dictArray 字典数组 @return 当前类的对象数组
*/
+ (NSArray *)ys_objectsWithDictionaryArray:(NSArray<NSDictionary *> *)dictArray; @end
2、下面我们来实现里面的方法,以后就用它来获取类/对象的属性、成员变量、方法和协议
说明一下:最主要的方法是在objc/runtime.h,这里只是列举了一些,起到抛砖引玉的作用
#import "NSObject+YSRuntime.h"
#import <objc/runtime.h> @implementation NSObject (YSRuntime) #pragma mark - 属性数组
const char *propertiesKey = "ys.propertiesList";
+ (NSArray *)ys_propertiesList { // 获取关联对象
NSArray *result = objc_getAssociatedObject(self, propertiesKey); if (result != nil) {
return result;
} unsigned int count = ;
objc_property_t *list = class_copyPropertyList([self class], &count); NSMutableArray *arrayM = [NSMutableArray array]; for (unsigned int i = ; i < count; i++) { objc_property_t pty = list[i]; const char *cName = property_getName(pty);
NSString *name = [NSString stringWithUTF8String:cName]; [arrayM addObject:name];
} free(list); // 设置关联对象
objc_setAssociatedObject(self, propertiesKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC); return objc_getAssociatedObject(self, propertiesKey);
} #pragma mark - 私有方法,专门针对字典转模型中的自定义属性,{@"name":@"Dog"},name是属性名,Dog是自定义的模型类,属性名-属性类型
const char *propertiesTypeKey = "ys.propertiesTypeKey";
+ (NSArray<NSDictionary *> *)ys_propertiesAndTypeList { // 获取关联对象
NSArray *result = objc_getAssociatedObject(self, propertiesTypeKey); if (result != nil) {
return result;
} unsigned int count = ;
objc_property_t *list = class_copyPropertyList([self class], &count); NSMutableArray<NSDictionary *> *arrayM = [NSMutableArray<NSDictionary *> array]; for (unsigned int i = ; i < count; i++) { objc_property_t pty = list[i]; const char *cType = property_getAttributes(pty);
NSString *typeStr = [NSString stringWithUTF8String:cType]; if([typeStr containsString:@"\",&"]){
NSRange typeRange = [typeStr rangeOfString:@"\",&"];
NSString *type = [typeStr substringWithRange:NSMakeRange(, typeRange.location - )]; const char *cName = property_getName(pty);
NSString *name = [NSString stringWithUTF8String:cName]; NSDictionary *dict = @{name:type}; [arrayM addObject:dict];
}
} free(list); // 设置关联对象
objc_setAssociatedObject(self, propertiesTypeKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC); return objc_getAssociatedObject(self, propertiesTypeKey);
} #pragma mark - 成员变量数组
const char *ivarsKey = "ys.ivarsList";
+ (NSArray *)ys_ivarsList { // 获取关联对象
NSArray *result = objc_getAssociatedObject(self, ivarsKey); if (result != nil) {
return result;
} unsigned int count = ;
Ivar *list = class_copyIvarList([self class], &count); NSMutableArray *arrayM = [NSMutableArray array]; for (unsigned int i = ; i < count; i++) { Ivar ivar = list[i]; const char *cName = ivar_getName(ivar);
NSString *name = [NSString stringWithUTF8String:cName]; [arrayM addObject:name];
} free(list); // 设置关联对象
objc_setAssociatedObject(self, ivarsKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC); return objc_getAssociatedObject(self, ivarsKey);
} #pragma mark - 方法数组
+ (NSArray *)ys_methodList { unsigned int count = ;
Method *list = class_copyMethodList([self class], &count); NSMutableArray *arrayM = [NSMutableArray array]; for (unsigned int i = ; i < count; i++) { Method method = list[i]; SEL selector = method_getName(method);
NSString *name = NSStringFromSelector(selector); [arrayM addObject:name];
} free(list); return arrayM.copy;
} #pragma mark - 协议数组
+ (NSArray *)ys_protocolList { unsigned int count = ;
__unsafe_unretained Protocol **list = class_copyProtocolList([self class], &count); NSMutableArray *arrayM = [NSMutableArray array]; for (unsigned int i = ; i < count; i++) { Protocol *protocol = list[i]; const char *cName = protocol_getName(protocol);
NSString *name = [NSString stringWithUTF8String:cName]; [arrayM addObject:name];
} free(list); return arrayM.copy;
} #pragma mark - 字典 -> 当前类的对象
+ (instancetype)ys_objectWithDictionary:(NSDictionary *)dictionary{ // 当前类的属性数组
NSArray *list = [self ys_propertiesList]; NSArray<NSDictionary *> *propertyTypeList = [self ys_propertiesAndTypeList]; id obj = [self new]; for (NSString *key in dictionary) { if([list containsObject:key]){ if ([dictionary[key] isKindOfClass:[NSDictionary class]]){ // 属性值为字典 for(NSDictionary *dict in propertyTypeList){ if([key isEqualToString: [NSString stringWithFormat:@"%@",dict.allKeys.firstObject]]){ NSString *classTypeStr = dict[key];
Class class = NSClassFromString(classTypeStr); id objChild = [class ys_objectWithDictionary:dictionary[key]]; [obj setValue:objChild forKey:key];
}
} }
else if([dictionary[key] isKindOfClass:[NSArray<NSDictionary *> class]]){ // 属性值为字典数组 }
else{
[obj setValue:dictionary[key] forKey:key];
}
}
} return obj;
} #pragma mark - 字典数组 -> 当前类的对象数组
+ (NSArray *)ys_objectsWithDictionaryArray:(NSArray<NSDictionary *> *)dictArray { if (dictArray.count == ) {
return nil;
} // 当前类的属性数组
NSArray *list = [self ys_propertiesList]; NSArray<NSDictionary *> *propertyTypeList = [self ys_propertiesAndTypeList]; NSMutableArray *arrayM = [NSMutableArray array];
for (NSDictionary *dictionary in dictArray) { id obj = [self new]; for (NSString *key in dictionary) { if([list containsObject:key]){ if ([dictionary[key] isKindOfClass:[NSDictionary class]]){ // 属性值为字典 for(NSDictionary *dict in propertyTypeList){ if([key isEqualToString: [NSString stringWithFormat:@"%@",dict.allKeys.firstObject]]){ NSString *classTypeStr = dict[key];
Class class = NSClassFromString(classTypeStr); id objChild = [class ys_objectWithDictionary:dictionary[key]]; [obj setValue:objChild forKey:key];
}
} }
else if([dictionary[key] isKindOfClass:[NSArray<NSDictionary *> class]]){ // 属性值为字典数组 }
else{
[obj setValue:dictionary[key] forKey:key];
}
}
} [arrayM addObject:obj];
} return arrayM.copy;
} @end
3、和YYModel一样,如果对象的一个属性为另一个自定义对象,那么同样可以起到连转的作用;
4、但比较遗憾的是,也是和YYModel一样,如果有一个属性是数组,又添加了泛型约束,没有取到这个数组的泛型约束。
我记得,YYModel就有这个问题,因为取不到泛型约束,所以当有属性为数组的时候,需要手动指定数组里面的元素类型。
希望各位大神看到后不吝赐教。
5、最后贴出一个小且非常有趣的小东东,里面的key就是我用上面的 “ys_ivarsList” 获取到所有成员变量,然后一级一级找的^_^
// 设置随机颜色给Application的statusBar,从此妈妈再也不用担心statusBar的背景色
id bgStyle = [[UIApplication sharedApplication] valueForKeyPath:@"statusBar.backgroundView.style"];
[bgStyle setValue:[UIColor redColor] forKey:@"backgroundColor"];
// frame = (5 649; 55 13)
// 修改高德地图和logo,删除和替换自己随意定
UIImageView *imgV = [mapView valueForKey:@"logoImageView"]; // 这就就是高德地图的logo
imgV.image = nil; // 我们把imageView的图片置为nil
[mapView setValue:imgV forKey:@"logoImageView"]; // 哈哈,这个高德地图的logo就不见了,妈妈从此再也不需要担心logo了
福利->KVC+Runtime获取类/对象的属性/成员变量/方法/协议并实现字典转模型的更多相关文章- Runtime获取类的属性列表和方法列表
Runtime获取类的属性列表和方法列表 Runtime很强大,他使得OC中没有真正意义上的私有属性和私有方法,我们可以利用OC的运行时拿到一个类的任何方法和任何属性,然后动态的去调用方法,objc_ ...
- JAVA反射机制教程-获取类对象
1. 什么是类对象 类对象,就是用于描述这种类,都有什么属性,什么方法的 2. 获取类对象 获取类对象有3种方式(1). Class.forName(2). Hero.class(3). new He ...
- Python脚本控制的WebDriver 常用操作 <;十七>; 获取测试对象的属性及内容
测试用例场景 获取测试对象的内容是前端自动化测试里一定会使用到的技术.比如我们要判断页面上是否显示了一个提示,那么我们就需要找到这个提示对象,然后获取其中的文字,再跟我们的预期进行比较.在webdri ...
- WPFS数据绑定(要是后台类对象的属性值发生改变,通知在“client界面与之绑定的控件值”也发生改变须要实现INotitypropertyChanged接口)
WPFS数据绑定(要是后台类对象的属性值发生改变,通知在"client界面与之绑定的控件值"也发生改变须要实现INotitypropertyChanged接口) MainWindo ...
- 获取JSON对象的属性值
1.问题背景 有一个json对象,其中有键值对,那怎样获取json对象中属性值 2.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...
- 获取JSON对象的属性名称
1.问题背景 一个json对象,是以键值对组成,通过循环json对象,获取json对象中的属性名称 2.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD ...
- Python 获取类对象的父类
参考 Get parent class name? Python 获取类对象的父类 给定一个类的对象a,要求获取该对象的父类. 方法: a.__class__.__bases__ 返回由该对象的父类组 ...
- CWnd和HWND的区别(hWnd只是CWnd对象的一个成员变量,代表与这个对象绑定的窗口)
所有控件类都是CWnd类的派生类,CWnd的所有成员函数在控件类中都可以使用.在MFC中,CWnd类是一个很重要的类,它封装了Windows的窗口句柄HWND.在Windows编程中, ...
- 对List对象按照某个成员变量进行排序
/** * 对List对象按照某个成员变量进行排序 * @param list List对象 * @param sortField 排序的属性名称 * @param sortMode 排序方式:ASC ...
随机推荐- java 实现一个简易计算器
import java.util.Scanner;public class Test { public static void main(String[] args) { count(); } pub ...
- WPF ItemsControl ListBox ListView比较
在进行列表信息展示时,WPF中提供多种列表可供选择.这篇博客将对WPF ItemsControl, ListBox, ListView进行比较. 相同点: 1. 这三个控件都是列表型控件,可以进行列表 ...
- 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同 ...
- [转]Ubuntu中无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)
sudo apt-get install git E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用) E: 无法锁定管理目录(/var/lib/dpkg/ ...
- js获取屏幕(设备)宽高
平常获取设备的宽高无非就那几 <script language="javascript"> var h = ""; h += " 网页可见 ...
- 转载 Java基本数据类型
Java语言是静态类型的(statical typed),也就是说所有变量和表达式的类型再编译时就已经完全确定.由于是statical typed,导致Java语言也是强类型(Strong typed ...
- 使用.NET Core快速开发一个较正规的命令行应用程序
程序员的世界,命令行工具一直是"体验非常友好"的工具,也能自动化完成很多事情,同时还能结合shell来进行某项任务的批处理(脚本).在.NET Core中,命令行应用程序是基础,但 ...
- Linux使用scp远程传输命令进行服务器文件互传(阿里云服务器)
阿里云同一个区的的两个云服务器,通过内网进行文件传输,速度快不说(正常传输文件的速度能达到35m~50m/s),还不占用公网带宽. 阿里云云服务器有一个安全组策略,可能需要设置下 内网入.出方向的IP ...
- 如何解决VC ";应用程序无法启动,因为应用程序的并行配置不正确 sxstrace.exe";问题
引用链接 http://blog.csdn.net/pizi0475/article/details/7790992 应用程序事件日志中: “C:\windows\system32\test.exe” ...
- 仿美团ViewPager+GridView
在接下来我要实现一个仿美团的效果 1.首先写一个登录注册界面用到了,很简单... 这里要提醒各位在调用方法时有set... 也有add.... 的方法,为了严谨可以做些正则判断手机号,用se ...
Runtime获取类的属性列表和方法列表 Runtime很强大,他使得OC中没有真正意义上的私有属性和私有方法,我们可以利用OC的运行时拿到一个类的任何方法和任何属性,然后动态的去调用方法,objc_ ...
1. 什么是类对象 类对象,就是用于描述这种类,都有什么属性,什么方法的 2. 获取类对象 获取类对象有3种方式(1). Class.forName(2). Hero.class(3). new He ...
测试用例场景 获取测试对象的内容是前端自动化测试里一定会使用到的技术.比如我们要判断页面上是否显示了一个提示,那么我们就需要找到这个提示对象,然后获取其中的文字,再跟我们的预期进行比较.在webdri ...
WPFS数据绑定(要是后台类对象的属性值发生改变,通知在"client界面与之绑定的控件值"也发生改变须要实现INotitypropertyChanged接口) MainWindo ...
1.问题背景 有一个json对象,其中有键值对,那怎样获取json对象中属性值 2.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...
1.问题背景 一个json对象,是以键值对组成,通过循环json对象,获取json对象中的属性名称 2.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD ...
参考 Get parent class name? Python 获取类对象的父类 给定一个类的对象a,要求获取该对象的父类. 方法: a.__class__.__bases__ 返回由该对象的父类组 ...
所有控件类都是CWnd类的派生类,CWnd的所有成员函数在控件类中都可以使用.在MFC中,CWnd类是一个很重要的类,它封装了Windows的窗口句柄HWND.在Windows编程中, ...
/** * 对List对象按照某个成员变量进行排序 * @param list List对象 * @param sortField 排序的属性名称 * @param sortMode 排序方式:ASC ...
- java 实现一个简易计算器
import java.util.Scanner;public class Test { public static void main(String[] args) { count(); } pub ...
- WPF ItemsControl ListBox ListView比较
在进行列表信息展示时,WPF中提供多种列表可供选择.这篇博客将对WPF ItemsControl, ListBox, ListView进行比较. 相同点: 1. 这三个控件都是列表型控件,可以进行列表 ...
- 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同 ...
- [转]Ubuntu中无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)
sudo apt-get install git E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用) E: 无法锁定管理目录(/var/lib/dpkg/ ...
- js获取屏幕(设备)宽高
平常获取设备的宽高无非就那几 <script language="javascript"> var h = ""; h += " 网页可见 ...
- 转载 Java基本数据类型
Java语言是静态类型的(statical typed),也就是说所有变量和表达式的类型再编译时就已经完全确定.由于是statical typed,导致Java语言也是强类型(Strong typed ...
- 使用.NET Core快速开发一个较正规的命令行应用程序
程序员的世界,命令行工具一直是"体验非常友好"的工具,也能自动化完成很多事情,同时还能结合shell来进行某项任务的批处理(脚本).在.NET Core中,命令行应用程序是基础,但 ...
- Linux使用scp远程传输命令进行服务器文件互传(阿里云服务器)
阿里云同一个区的的两个云服务器,通过内网进行文件传输,速度快不说(正常传输文件的速度能达到35m~50m/s),还不占用公网带宽. 阿里云云服务器有一个安全组策略,可能需要设置下 内网入.出方向的IP ...
- 如何解决VC ";应用程序无法启动,因为应用程序的并行配置不正确 sxstrace.exe";问题
引用链接 http://blog.csdn.net/pizi0475/article/details/7790992 应用程序事件日志中: “C:\windows\system32\test.exe” ...
- 仿美团ViewPager+GridView
在接下来我要实现一个仿美团的效果 1.首先写一个登录注册界面用到了,很简单... 这里要提醒各位在调用方法时有set... 也有add.... 的方法,为了严谨可以做些正则判断手机号,用se ...