Runtime 運行時之四:動態(tài)創(chuàng)建類和對象哪亿、實例操作函數(shù)粥烁、獲取類定義

動態(tài)創(chuàng)建對象

動態(tài)創(chuàng)建對象的函數(shù)如下:

// 創(chuàng)建類實例
id class_createInstance ( Class cls, size_t extraBytes );
// 在指定位置創(chuàng)建類實例
id objc_constructInstance ( Class cls, void *bytes );
// 銷毀類實例
void * objc_destructInstance ( id obj );
  • class_createInstance函數(shù):創(chuàng)建實例時,會在默認的內(nèi)存區(qū)域為類分配內(nèi)存锣夹。extraBytes參數(shù)表示分配的額外字節(jié)數(shù)页徐。這些額外的字節(jié)可用于存儲在類定義中所定義的實例變量之外的實例變量。該函數(shù)在ARC環(huán)境下無法使用银萍。

調用class_createInstance的效果與+alloc方法類似变勇。不過在使用class_createInstance時,我們需要確切的知道我們要用它來做什么贴唇。在下面的例子中搀绣,我們用NSString來測試一下該函數(shù)的實際效果:

id theObject = class_createInstance(NSString.class, sizeof(unsigned));
 
id str1 = [theObject init];
NSLog(@"%@", [str1 class]);
id str2 = [[NSString alloc] initWithString:@"test"];
NSLog(@"%@", [str2 class]);
輸出結果是:
2014-10-23 12:46:50.781 RuntimeTest[4039:89088] NSString
2014-10-23 12:46:50.781 RuntimeTest[4039:89088] __NSCFConstantString

可以看到,使用class_createInstance函數(shù)獲取的是NSString實例戳气,而不是類簇中的默認占位符類__NSCFConstantString链患。

  • objc_constructInstance函數(shù):在指定的位置(bytes)創(chuàng)建類實例。

  • objc_destructInstance函數(shù):銷毀一個類的實例瓶您,但不會釋放并移除任何與其相關的引用麻捻。

實例操作函數(shù)

實例操作函數(shù)主要是針對我們創(chuàng)建的實例對象的一系列操作函數(shù),我們可以使用這組函數(shù)來從實例對象中獲取我們想要的一些信息呀袱,如實例對象中變量的值贸毕。這組函數(shù)可以分為三小類:
1.針對整個對象進行操作的函數(shù),這類函數(shù)包含

// 返回指定對象的一份拷貝
id object_copy ( id obj, size_t size );
// 釋放指定對象占用的內(nèi)存
id object_dispose ( id obj );

有這樣一種場景夜赵,假設我們有類A和類B明棍,且類B是類A的子類。類B通過添加一些額外的屬性來擴展類A】苌現(xiàn)在我們創(chuàng)建了一個A類的實例對象摊腋,并希望在運行時將這個對象轉換為B類的實例對象,這樣可以添加數(shù)據(jù)到B類的屬性中嘁傀。這種情況下兴蒸,我們沒有辦法直接轉換,因為B類的實例會比A類的實例更大细办,沒有足夠的空間來放置對象类咧。此時,我們就要以使用以上幾個函數(shù)來處理這種情況蟹腾,如下代碼所示:

NSObject *a = [[NSObject alloc] init];
id newB = object_copy(a, class_getInstanceSize(MyClass.class));
object_setClass(newB, MyClass.class);
object_dispose(a);

2.針對對象實例變量進行操作的函數(shù)痕惋,這類函數(shù)包含:

// 修改類實例的實例變量的值
Ivar object_setInstanceVariable ( id obj, const char *name, void *value );
// 獲取對象實例變量的值
Ivar object_getInstanceVariable ( id obj, const char *name, void **outValue );
// 返回指向給定對象分配的任何額外字節(jié)的指針
void * object_getIndexedIvars ( id obj );
// 返回對象中實例變量的值
id object_getIvar ( id obj, Ivar ivar );
// 設置對象中實例變量的值
void object_setIvar ( id obj, Ivar ivar, id value );

如果實例變量的Ivar已經(jīng)知道,那么調用object_getIvar會比object_getInstanceVariable函數(shù)快娃殖,相同情況下值戳,object_setIvar也比object_setInstanceVariable快。

3.針對對象的類進行操作的函數(shù)炉爆,這類函數(shù)包含:

// 返回給定對象的類名
const char * object_getClassName ( id obj );
// 返回對象的類
Class object_getClass ( id obj );
// 設置對象的類
Class object_setClass ( id obj, Class cls );

獲取類定義

Objective-C動態(tài)運行庫會自動注冊我們代碼中定義的所有的類堕虹。我們也可以在運行時創(chuàng)建類定義并使用objc_addClass函數(shù)來注冊它們卧晓。runtime提供了一系列函數(shù)來獲取類定義相關的信息,這些函數(shù)主要包括:

/ 獲取已注冊的類定義的列表
int objc_getClassList ( Class *buffer, int bufferCount );
// 創(chuàng)建并返回一個指向所有已注冊類的指針列表
Class * objc_copyClassList ( unsigned int *outCount );
// 返回指定類的類定義
Class objc_lookUpClass ( const char *name );
Class objc_getClass ( const char *name );
Class objc_getRequiredClass ( const char *name );
// 返回指定類的元類
Class objc_getMetaClass ( const char *name );
  • objc_getClassList函數(shù):獲取已注冊的類定義的列表赴捞。我們不能假設從該函數(shù)中獲取的類對象是繼承自NSObject體系的逼裆,所以在這些類上調用方法是,都應該先檢測一下這個方法是否在這個類中實現(xiàn)赦政。

下面代碼演示了該函數(shù)的用法:

int numClasses;
Class * classes = NULL;
numClasses = objc_getClassList(NULL, 0);
if (numClasses > 0) {
    classes = malloc(sizeof(Class) * numClasses);
    numClasses = objc_getClassList(classes, numClasses);
    NSLog(@"number of classes: %d", numClasses);
    for (int i = 0; i < numClasses; i++) {
        Class cls = classes[i];
        NSLog(@"class name: %s", class_getName(cls));
    }
    free(classes);
}
輸出結果:
2014-10-23 16:20:52.589 RuntimeTest[8437:188589] number of classes: 1282
2014-10-23 16:20:52.589 RuntimeTest[8437:188589] class name: DDTokenRegexp
2014-10-23 16:20:52.590 RuntimeTest[8437:188589] class name: _NSMostCommonKoreanCharsKeySet
2014-10-23 16:20:52.590 RuntimeTest[8437:188589] class name: OS_xpc_dictionary
2014-10-23 16:20:52.590 RuntimeTest[8437:188589] class name: NSFileCoordinator
2014-10-23 16:20:52.590 RuntimeTest[8437:188589] class name: NSAssertionHandler
2014-10-23 16:20:52.590 RuntimeTest[8437:188589] class name: PFUbiquityTransactionLogMigrator
2014-10-23 16:20:52.591 RuntimeTest[8437:188589] class name: NSNotification
2014-10-23 16:20:52.591 RuntimeTest[8437:188589] class name: NSKeyValueNilSetEnumerator
2014-10-23 16:20:52.591 RuntimeTest[8437:188589] class name: OS_tcp_connection_tls_session
2014-10-23 16:20:52.591 RuntimeTest[8437:188589] class name: _PFRoutines
......還有大量輸出
  • 獲取類定義的方法有三個:objc_lookUpClass, objc_getClass和objc_getRequiredClass胜宇。如果類在運行時未注冊,則objc_lookUpClass會返回nil恢着,而objc_getClass會調用類處理回調桐愉,并再次確認類是否注冊,如果確認未注冊掰派,再返回nil从诲。而objc_getRequiredClass函數(shù)的操作與objc_getClass相同,只不過如果沒有找到類靡羡,則會殺死進程系洛。

  • objc_getMetaClass函數(shù):如果指定的類沒有注冊,則該函數(shù)會調用類處理回調略步,并再次確認類是否注冊描扯,如果確認未注冊,再返回nil纳像。不過荆烈,每個類定義都必須有一個有效的元類定義拯勉,所以這個函數(shù)總是會返回一個元類定義竟趾,不管它是否有效。

參考:
http://southpeak.github.io/2014/10/25/objective-c-runtime-1/

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宫峦,一起剝皮案震驚了整個濱河市岔帽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌导绷,老刑警劉巖犀勒,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異妥曲,居然都是意外死亡贾费,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門檐盟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來褂萧,“玉大人,你說我怎么就攤上這事葵萎〉加蹋” “怎么了唱凯?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長谎痢。 經(jīng)常有香客問我磕昼,道長,這世上最難降的妖魔是什么节猿? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任票从,我火速辦了婚禮,結果婚禮上沐批,老公的妹妹穿的比我還像新娘纫骑。我一直安慰自己,他們只是感情好九孩,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布先馆。 她就那樣靜靜地躺著,像睡著了一般躺彬。 火紅的嫁衣襯著肌膚如雪煤墙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天宪拥,我揣著相機與錄音仿野,去河邊找鬼。 笑死她君,一個胖子當著我的面吹牛脚作,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缔刹,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼球涛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了校镐?” 一聲冷哼從身側響起亿扁,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸟廓,沒想到半個月后从祝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡引谜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年牍陌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片员咽。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡毒涧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出骏融,到底是詐尸還是另有隱情链嘀,我是刑警寧澤萌狂,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站怀泊,受9級特大地震影響茫藏,放射性物質發(fā)生泄漏。R本人自食惡果不足惜霹琼,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一务傲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧枣申,春花似錦售葡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至模孩,卻和暖如春尖阔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背榨咐。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工介却, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人块茁。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓齿坷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親数焊。 傳聞我的和親對象是個殘疾皇子永淌,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容