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也是運用了這個動態的原理來實現的。

相關文章
相關標籤/搜索