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

1.什么是动态特性?

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

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

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

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

 

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


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

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


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

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


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

 

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

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

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

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

 

(上面是最长见的使用方式,有人问我可否不事先定义类型,而后利用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)code

因而,只能放弃事先定义类的方式,转而利用在动态建立类时(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也是运用了这个动态的原理来实现的。

相关文章
相关标签/搜索