文档章节

iOS动态特性初研究(利用JSON动态创建类型和对象)

whj
 whj
发布于 2014/03/06 18:01
字数 1677
阅读 5495
收藏 8

1.什么是动态特性?

程序可以访问,检测和修改它本身状态或行为的能力。用我自己的理解,这里的状态和行为,理解成变量,属性和方法,会更加形象一点。

2.与动态特性相关的概念,selector,IMP,Class

Class: 从语法形式上看,和UIButton,NSString一样,是一种类型。

Class被定义为一个指向objc_class的结构体指针

 

它是指向对象的类结构体的指针,该类结构体含有一个指向其父类类结构的指访类方法的表,该类方法的存以及其他必要信息。


除了静态方法来创建对象,还可以使用string来创建,NSClassFromString。

SEL:定义成一个指向objc_selector指针


运行时,会在方法链表中根据SEL查找具体的实现方法IMP。为什么不用函数指针直接调用,而加了一层SEL?我的理解,首先Object-C不能直接用函数指这样只能做一个@selector法来取(本人在OC中写机,用函数指形式写action,但一直报错,只能用selector代替);其次,SEL可以配合动态方法来使用,例如NSSelectorFromString,performSelector,动态添加方法,并执行。

IMP:就是定义一个函数指针的形式


它包含一个接受消息的对象(self指针),调用方法SEL,以及若干参数,并返回一个id。

 

3. 举例子,如何将JSON直接映射成对象,如何将对象直接映射成DB(coreData原理)

3.1定义该类的属性,方法,生成对象。

用动态方法,获得该对象的属性/变量列表(class_copyPropertyList/class_copyIvarList),遍历获得每个属性的名称(property_getName),然后将JSON转换Dic,用key-value(setvalueForkey,valueForKey)方法,对对象进行赋值,取值操作。

此种方法,抽象出了公用的setter方法(用dictionary給对象赋值),但是缺点是,类型要事先定义。无法动态生成类型。这种例子,网上很多,而且不明白为什么例子中都把property name和attribute值打印出来,至于怎么用,半个字都没提?

 

(上面是最长见的使用方式,有人问我能否不事先定义类型,然后利用JSON来创建类型呢?这个还把我问住了)后来查阅OC runtime guide,发现有动态添加变量的方法(class_addIvar),于是思路由此打开:

3.2首先定义一个空的类

(没有属性,变量,方法),只有一个类名,然后运行时,給该类添加变量(当时没有查到可以动态添加属性的方法,后来发现有,但是要到iOS4.3以后才行),随后用給变量赋值。但是结果让人失望,无法动态添加变量。原因是class_addIvar只能在动态创建类型的时候,添加变量,也就是“class_addIvar"This function may only be called after objc_allocateClassPair and beforeobjc_registerClassPair.Adding an instance variable to an existing class is notsupported”,而事先定义类是静态创建的类,故无法在runtime时添加变量(http://stackoverflow.com/questions/17888877/objective-c-add-property-in-runtime)

于是,只能放弃事先定义类的方式,转而利用在动态创建类时(objc_allocateClassPair),添加变量 。然后用給变量赋值和取值的方式(object_setInstanceVariable,object_getIvar,注意,无法用key-value的方式操作,这种方法只有静态定义属性后才行),但这种方式,就只能用纯C的方式封装,赋值,取值都要传进obj参数,比较繁琐,没有面向对象那么方便。

结论:3.2中的结论,如果编译前定义类,那么无法用runtime添加变量,这种方法行不通;只有在runtime时,在objc_allocateClassPair和objc_registerClassPair之间用class_addIvar添加变量

 

3.3后来查到有动态添加property的方法 

(class_addProperty),在4.3之后。于是想到一种动态创建类型,并且可以用OC语法的方式访问变量。

首先,动态创建类型,添加变量(这个很重要,因为当我们访问property时,实际上是要对变量操作,如果没有添加变量,那么就是null),注册类型,然后往里动态添加属性,随后就可以象OC一样方便访问属性了 (因为静态类中属性会默认有一个和它同名的变量,对属性操作,实际上是对该变量操作)。

但实际上对该属性赋值后,取值却是null。因为只有在编译前定义的属性才会默认一个变量,property实际上只是提供了setter和getter的方法,至于你要把值存贮在哪里,需要自己设定,所以还需要在class_addProperty方法后,添加property的setter,getter,并在其中确定需要把值保存到哪里,从哪里取值。


getter


setter



这样我们就能用ClassA objA; [objAsetxxx:xxx]; [objA xxx]的方法来访问属性了(本人写了一个简单的实现,但暂时无法上传github,稍后会上传,请各位上传)

 

3.4使用动态创建类,对象,以及ORM的优点,缺点

这个例子有如下几个特点:1.可以动态生成类型 2.可以用OC的方式访问属性。纯粹的“动态”。

当然也有美中不足的地方,首先动态创建对象的类型都是id类型(因为是动态创建,事先没有定义具体类型),视觉上不直观。其次编译过程中,会报warning,因为property是动态添加的,不是编译之前确定的,所以编译器不知道setter,getter方法哪里来的。(当然可以用performSelector来调用就没有warning问题,但是调用方式太繁琐)

但是不影响使用。


结果


结论:3.3的方法比3.2,3.1的方法牛逼,直接动态创建类型和对象,但是牺牲的是code的可读性和可维护性,研究的意义大于实用意义。 


注意:这里需要大家研究的是,如何通过JSON的值,确定动态添加的变量和property的类型,我的思路是,可以容易区分NSString和NSNumber,但是如果确定int,long,float, long long等类型?应该可以通过值的大小范围来确定,例如int -256~255

 

3.5如何将对象映射进DB中,其实原理是一样的,可以运行时,获得类名,属性名,属性类型,值,然后用sqlite3的接口创建表,列,值,类型等等。其实Coredata也是运用了这个动态的原理来实现的。


本文转载自:http://blog.csdn.net/zhengyueyang71104233/article/details/14101373

共有 人打赏支持
whj

whj

粉丝 20
博文 32
码字总数 6865
作品 0
海淀
私信 提问
BlackHat & DEFCON现场秀:阿里安全专家演示“视频水印叠加”和“一分钟越狱iOS 11.4”

美国当地时间8月8日,两大世界顶级信息安全会议BlackHat和DEFCON将在美国拉斯维加斯正式揭幕。来自全球的数万名白帽黑客、安全厂商、高校学者、政府机构等安全从业人员齐聚,高度关注这两场盛...

华蒙
08/08
0
0
iOS源码补完计划--AFNetworking(二)

目录 前言 AFNetworkReachabilityManager.h AFNetworkReachabilityManager.m API注释Demo 参考资料 前言 AFNetworking源码第二篇 主要看了看AFNetworkReachabilityManager的内容 作为一个辅助...

kirito_song
05/16
0
0
多伦多大学开发反面部识别系统 人脸识别率降至0.5%

多伦多大学开发反面部识别系统 人脸识别率降至0.5% 2018-06-06 13:30编辑: CuiTong分类:AI来源:青亭网 人工智能AI反面部识别 招聘信息: C++工程师 Cocos2d-x游戏客户端开发 iOS开发工程师...

CuiTong
06/06
0
0
BlackHat 2018 iOS越狱细节揭秘:危险的用户态只读内存

  议题概要   现代操作系统基本都已经在硬件级别(MMU)支持了用户态只读内存,只读内存映射在保证了跨进程间通信、用户态与内核间通信高效性的同时,也保证了其安全性。直到DirtyCOW漏洞...

FreeBuf
08/09
0
0
2018 一份"有点难"的iOS面试题(5年iOS开发)

序言: 之前一时兴致在本站上出过一份iOS的中级面试题,引起一些关注,不少同学表示对”隐藏关卡“感兴趣。升级版iOS面试题来了,目测难倒90%iOS程序员,目测一大波程序员撸着袖子在靠近。 ...

原来是泽镜啊
05/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

MariaDB 服务器在 MySQL Workbench 备份数据的时候出错如何解决

服务器是运行在 MariaDB 10.2 上面的,在使用 MySQL Workbench 出现错误: mysqldump: Couldn't execute 'SELECT COLUMN_NAME, JSON_EXTRACT(HISTOGRAM, '$."number-of-buckets-specified"'......

honeymose
今天
1
0
apache顶级项目(二) - B~C

apache顶级项目(二) - B~C https://www.apache.org/ Bahir Apache Bahir provides extensions to multiple distributed analytic platforms, extending their reach with a diversity of s......

晨猫
今天
4
0
day152-2018-11-19-英语流利阅读

“超级食物”竟然是营销噱头? Daniel 2018-11-19 1.今日导读 近几年来,超级食物 superfoods 开始逐渐走红。不难发现,越来越多的轻食餐厅也在不断推出以超级食物为主打食材的健康料理,像是...

飞鱼说编程
今天
10
0
SpringBoot源码:启动过程分析(二)

接着上篇继续分析 SpringBoot 的启动过程。 SpringBoot的版本为:2.1.0 release,最新版本。 一.时序图 一样的,我们先把时序图贴上来,方便理解: 二.源码分析 回顾一下,前面我们分析到了下...

Jacktanger
昨天
4
0
Apache防盗链配置,Directory访问控制,FilesMatch进行访问控制

防盗链配置 通过限制referer来实现防盗链的功能 配置前,使用curl -e 指定referer [root@test-a test-webroot]# curl -e "http://www.test.com/1.html" -x127.0.0.1:80 "www.test.com/1.jpg......

野雪球
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部