iOS  反射 学习 和 运用

反射:  通过 类名来获得生成的相应的类的实例 的这种机制  叫 反射

常用的反射方式

  1. 把 NSDictionary  转成 自定义 model
  2. 自定义 model 转成  NSDictionary

(1)第一种 其实很好实现的 ,你可以自己写映射关系 对应 ,也可以使用一些优秀的第三方,比如 MJExtension 等  特别方便

(2)MJExtension 有一个方法  valueKey,  这个 是可以转字典

但是这种方法是有局限的  当这个 比较适合 单层次的model类  不适合 自己子类 有自定义model 或者 自己本身是继承于其他自定义model的派生类

因为很多时候我想转成字典  我是想把它通过字典转json 做缓存 ,如果 这个字典 中有自定义类 (另外 如果有UI类型的类 比如 UIColor  UIView UILabel 等非数据级别的) 会在转成json的过程中因不被识别导致失败 而崩溃.

在网上查了 好多资料  有很多类似的说法

”对象的类,如果是派生类,就得靠其他方式来实现了,因为得到不该基类的属性”  (错误的一句话,上网 搜去 一大堆)

看到 各种转载 之后 甚至 自己都怯步了 靠 我能做到吗?

现在我可以说  能啊 用脚想 实际运用的时候 不就是通过点语法获取 父类/子类的属性 或者方法的么  反过来 为啥不行 ?

Java C# 反射很常见   iOS也一定行!!!

关键代码来了

先上几个要点

反射 动用了 底层 主要是 c 语言

(1)头文件  #import <objc/runtime.h>

(2) 算法策略 DFS  

(3)  通过调用自身的class方法获取当前类的元数据信息

     通过runtime的 class_copyPropertyList 方法取得当前类的属性列表,以指针数组的形  式返  回

     遍历指针数组,通过property_getName获取属性名,property_getAttributes获取属性类型

(4)判断条件 

  a.  用[value class]得到的都是 JKArray JKdictionary  __NSCFString __NSCFConstantString 等 类簇级别的  他们的父类的父类 或者说 他们 是 NSString  等 的一个小子类,判断冗余条件太多 不容易穷尽 也不够科学  所以 获取类 必须用 property_getAttributes来取 才能取到 NSString NSArray 等 NS级别的 

转化后 是一个字符串 类型的类 

再转换成类 方法是:

Class propertyClass = NSClassFromString(className); 

这种方法优势是动态获取 甚至不用 添加 头文件 来制约 甚是方便,因为 类 在搜索过程中 他本来就是从物理条件 匿名 出发  你不可能提前角度 知道 你将要搜索到什么类

b. 关键就是 节点检索条件

 我设计的是  

向下:如果当前节点 是一个 系统级别的类 那么它已经是叶子节点   否则 需要进一步DFS

向上:DFS  当前类的 superClass  

结束条件: class 为空 或者 已经到 基类 NSObject 

判断 是否 是系统级别的类方法

if (propertyClass == NULL) {

} else {

    NSBundle *mainB = [NSBundle bundleForClass:propertyClass];
if (mainB == [NSBundle mainBundle]) {
DLog(@"自定义的类");
} else {
DLog(@"系统的类");
// if (propertyClass == [UIColor class]) { //看需求 处理
// continue;
// }
}
}

原理:就是看这个类 是不是在沙盒里 在  肯定是系统级别的,否则 是 自定义的

上代码:

//
// NSDictionary+ModelConvert.h
// dailylife
//
// Created by HF on 16/3/9.
//
// #import <Foundation/Foundation.h> @interface NSDictionary (ModelConvert) /**
* 拓展 获得当前类 及 子类 和 父类 的全部 属性和属性值
* get current object as well as the properties inherited from the parent classes
* @returns (NSString) Dictionary of property name --> value
*
* 注意 不应该 使用 UI 的类 做处理 可以生成字典 但是转json会崩溃
*/
+ (NSDictionary *)toDictionaryFromModel:(id)objectModel; @end
//
// NSDictionary+ModelConvert.m
// dailylife
//
// Created by HF on 16/3/9.
//
// #import "NSDictionary+ModelConvert.h"
#import <objc/runtime.h> @implementation NSDictionary (ModelConvert) + (NSDictionary *)toDictionaryFromModel:(id)objectModel{
return [NSDictionary classPropsForClassHierarchyObjectModel:objectModel
class:[objectModel class] onDictionary:[NSMutableDictionary dictionary]];
} static const char *getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
//printf("attributes=%s\n", attributes);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T' && attribute[1] != '@') {
// it's a C primitive type: // if you want a list of what will be returned for these primitives, search online for
// "objective-c" "Property Attribute Description Examples"
// apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc. NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
}
else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
// it's an ObjC id type:
return "id";
}
else if (attribute[0] == 'T' && attribute[1] == '@') {
// it's another ObjC object type:
NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
}
}
return "";
} + (NSDictionary *)classPropsForClassHierarchyObjectModel:(id)objectModel class:(Class)klass onDictionary:(NSMutableDictionary *)results
{
if (klass == NULL) {
return nil;
} //stop if we reach the NSObject class as is the base class
if (klass == [NSObject class]) {
return [NSDictionary dictionaryWithDictionary:results];
}
else{
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(klass, &outCount);
if (outCount == 0) {
free(properties);
return nil;
} for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
const char *propName = property_getName(property);
if(propName) {
NSString *propertyName = [NSString stringWithUTF8String:propName];
id value = [objectModel valueForKey:propertyName];
if (value) {
const char *propType = getPropertyType(property);
NSString *className = [NSString stringWithCString:propType
encoding:[NSString defaultCStringEncoding]];
Class propertyClass = NSClassFromString(className);
DLog(@"%@ == %@",className,NSClassFromString(className)); if (propertyClass == NULL) {
[results setObject:value forKey:propertyName];
} else { DLog(@"%@",propertyName);
DLog(@"%@",value);
DLog(@"%@",[value class]);
NSBundle *mainB = [NSBundle bundleForClass:propertyClass];
if (mainB == [NSBundle mainBundle]) {
DLog(@"自定义的类");
NSDictionary *dic = [NSDictionary toDictionaryFromModel:value]; //向下处理
[results setObject:dic forKey:propertyName];
} else {
DLog(@"系统的类");
if (propertyClass == [UIColor class]) {//看需求处理
continue;
}
[results setObject:value forKey:propertyName];
}
}
}
}
}
free(properties);
//go for the superclass
return [NSDictionary classPropsForClassHierarchyObjectModel:objectModel class:[klass superclass] onDictionary:results];//向上处理
}
} @end

参考 多重继承类

1.

2.

3.

使用:

运行打印

ShowDataFeedModel 还有个属性 是属性 是 foodTags  这里没打印 出来 是因为 value是空的  我没有 把 value为空的对象 放在 字典集合中 如果 需要的话 可以处理的  放进空数据就好了

这样的字典集合 可以直接转换成 json 存储  需要的 时候 再转换成 对应的 数据model  妥妥的

好的学习方法很重要, 拆第三方包 看究竟也不错 没准 能给自己一些启发

最重要的是 敢于实践和探究  有人说 不能实现 不一定吧  写完这篇博文 我能开心好几天

参考:

http://blog.csdn.net/yongyinmg/article/details/39890423 (从JSONModel看Objective-C的反射机制 )

iOS 反射 学习 和 运用的更多相关文章

  1. IOS基础学习-2: UIButton

    IOS基础学习-2: UIButton   UIButton是一个标准的UIControl控件,UIKit提供了一组控件:UISwitch开关.UIButton按钮.UISegmentedContro ...

  2. iOS阶段学习第一天笔记(Mac终端的操作)

    前言部分 原本从事的是.NET开发,一直在要不要转iOS 中犹豫徘徊,经过复杂的内心挣扎终于鼓起勇气辞职脱产学习iOS;希望通过四个月的 学习后能够拿到理想的薪资.以下是学习过程中的学习笔记,为了方便 ...

  3. ios网络学习------4 UIWebView的加载本地数据的三种方式

    ios网络学习------4 UIWebView的加载本地数据的三种方式 分类: IOS2014-06-27 12:56 959人阅读 评论(0) 收藏 举报 UIWebView是IOS内置的浏览器, ...

  4. ios网络学习------6 json格式数据的请求处理

    ios网络学习------6 json格式数据的请求处理 分类: IOS2014-06-30 20:33 471人阅读 评论(3) 收藏 举报 #import "MainViewContro ...

  5. iOS之学习资源收集--很好的IOS技术学习网站

    点击图片也能打开相关的网站: https://boxueio.com/skill/swift http://ios.b2mp.cn/ http://gold.xitu.io/welcome/?utm_ ...

  6. ios开发之OC基础-ios开发学习路线图

    本系列的文章主要来自于个人在学习前锋教育-欧阳坚老师的iOS开发教程之OC语言教学视频所做的笔记,边看视频,边记录课程知识点.建议大家先过一遍视频,在看视频的过程中记录知识点关键字,把把握重点,然后再 ...

  7. iOS手势学习UIGestureRecognizer & cocos2d 手势推荐

    iOS手势学习UIGestureRecognizer & cocos2d 手势推荐 手势识别类型: UILongPressGestureRecognizer  // 长按UIPanGestur ...

  8. Java 反射学习笔记

    要学反射,先要了解Class这个类,Class是所有Java类的一个总称,Class的实例中存储的是一个类的字节码,获取Class的实例有三种方式: System.class new Date().g ...

  9. 开源中国iOS客户端学习

    开源中国iOS客户端学习 续写前言 <开源中国iOS客户端学习>续写前系列博客    http://blog.csdn.net/column/details/xfzl-kykhd.html ...

随机推荐

  1. c++ using Handle Class Pattern to accomplish implementation hiding

    Reference material: Thinking In C++ 2nd eidition chapter 5 section "Handle classes" If the ...

  2. iOS中解析Bonjour服务(转)

    服务器端Bonjour服务发布成功之后,客户端可以通过NSNetService解析服务,解析成功后,可以获得通讯的数据细节,如:IP地址.端口等信息. 首先需要实例化NSNetService对象代码如 ...

  3. abp 中wangEditor-angular 的使用

    主要是上传图片的配置. (function () { if (typeof angular === 'undefined') { return; } angular.module('editorCon ...

  4. hdu5795 A Simple Nim 求nim求法,打表找sg值规律 给定n堆石子,每堆有若干石子,两个人轮流操作,每次操作可以选择任意一堆取走任意个石子(不可以为空) 或者选择一堆,把它分成三堆,每堆不为空。求先手必胜,还是后手必胜。

    /** 题目:A Simple Nim 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5795 题意:给定n堆石子,每堆有若干石子,两个人轮流操作,每次操作 ...

  5. 【spring boot】在spring boot下使用多线程

    使用场景: 方法处理到某一步,需要将信息交给另一个线程去处理!! =================================================================== ...

  6. WebMethod Session

    [WebMethod(EnableSession = true)] public static string SayHello() { LxUserContext depno = HttpContex ...

  7. urllib基本使用 urlopen(),Request

    urllib包含的常用模块:import urllib.request # 打开和读取url请求import urllib.error # 异常处理模块import urllib.parse # ur ...

  8. 1、easyUI-创建 CRUD普通dataGrid(表格)

    在实现功能之前,我们要做以下几个准备: 分以下几个步骤:开发工具,easyUI包,目录结构,创建数据库,创建相应的页面视图,后台代码编写,优化: 第一步:开发工具 我的开发工具是Hbuild,开发语言 ...

  9. SSL证书的生成

    openssl工具下载路径:链接:https://pan.baidu.com/s/1o0-s8OplHZt55Cio2HmjVA 密码:u759 1.使用openssl工具生成一个RSA秘钥      ...

  10. Linux 进程间通信(二)(网络IPC:套接字)

    socket描述符 套接字是通信端点的抽象,创建一个套接字使用如下函数: #include <sys/socket.h> int socket(int domain, int type, ...