動態(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/