程序能夠訪問,檢測和修改它自己狀態或行爲的能力。用我本身的理解,這裏的狀態和行爲,理解成變量,屬性和方法,會更加形象一點。git
Class: 從語法形式上看,和UIButton,NSString同樣,是一種類型。github
它是指向對象的類結構體的指針,該類結構體含有一個指向其父類類結構的指針,訪類方法的鏈表,該類方法的緩存以及其餘必要信息。見下圖objective-c
除了靜態方法來建立對象,還可使用string來建立,NSClassFromString。sql
運行時,會在方法鏈表中根據SEL查找具體的實現方法IMP。爲何不用函數指針直接調用,而加了一層SEL?個人理解,首先Object-C的類不能直接應用函數指針,這樣只能作一個@selector語法來取(本人在OC中寫過狀態機,用函數指針形式寫action,但一直報錯,只能用selector代替);其次,SEL還能夠配合動態方法來使用,例如NSSelectorFromString,performSelector,動態添加方法,並執行。ide
它包含一個接受消息的對象(self指針),調用方法SEL,以及若干參數,並返回一個id。函數
用動態方法,得到該對象的屬性/變量列表(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),因而思路由此打開:指針
(沒有屬性,變量,方法),只有一個類名,而後運行時,給該類添加變量(當時沒有查到能夠動態添加屬性的方法,後來發現有,可是要到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添加變量
(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,稍後會上傳,請各位上傳)
這個例子有以下幾個特色: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