收 集 文 章 / 超 人
文章出處
Rumtime方法說明
獲取類的類名
//如果傳入的cls為Nil丑慎,則返回一個字字符串珊佣。
const char * class_getName ( Class cls );
獲取類的父類
Class class_getSuperclass ( Class cls );
- class_getSuperclass函數(shù),當(dāng)cls為Nil或者cls為根類時,返回Nil抄肖。不過通常我們可以使用NSObject類的superclass方法來達到同樣的目的
判斷給定的Class是否是一個元類
//如果是cls是元類,則返回YES窖杀;如果否或者傳入的cls為Nil漓摩,則返回NO。
BOOL class_isMetaClass ( Class cls );
獲取實例大小
size_t class_getInstanceSize ( Class cls );
成員變量(ivars)及屬性
獲取類中指定名稱實例成員變量的信息
//返回一個指向包含name指定的成員變量信息的objc_ivar結(jié)構(gòu)體的指針(Ivar)
Ivar class_getInstanceVariable ( Class cls, const char *name );
獲取類成員變量的信息
Ivar class_getClassVariable ( Class cls, const char *name );
- 目前沒有找到關(guān)于Objective-C中類變量的信息陈瘦,一般認為Objective-C不支持類變量幌甘。注意潮售,返回的列表不包含父類的成員變量和屬性。
添加成員變量
BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
- Objective-C不支持往已存在的類中添加實例變量锅风,因此不管是系統(tǒng)庫提供的提供的類酥诽,還是我們自定義的類,都無法動態(tài)添加成員變量皱埠。但如果我們通過運行時來創(chuàng)建一個類的話肮帐,又應(yīng)該如何給它添加成員變量呢?這時我們就可以使用class_addIvar函數(shù)了边器。不過需要注意的是训枢,這個方法只能在objc_allocateClassPair函數(shù)與objc_registerClassPair之間調(diào)用。另外忘巧,這個類也不能是元類恒界。成員變量的按字節(jié)最小對齊量是1<
獲取整個成員變量列表
Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
- 返回一個指向成員變量信息的數(shù)組,數(shù)組中每個元素是指向該成員變量信息的objc_ivar結(jié)構(gòu)體的指針砚嘴。這個數(shù)組不包含在父類中聲明的變量十酣。outCount指針返回數(shù)組的大小。需要注意的是际长,我們必須使用free()來釋放這個數(shù)組耸采。
獲取指定的屬性
objc_property_t class_getProperty ( Class cls, const char *name );
獲取屬性列表
objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
- 獲取的是所有@property定義屬性
為類添加屬性
BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
替換類的屬性
void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
方法(methodLists)
添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
- class_addMethod的實現(xiàn)會覆蓋父類的方法實現(xiàn),但不會取代本類中已存在的實現(xiàn)工育,如果本類中包含一個同名的實現(xiàn)虾宇,則函數(shù)會返回NO。如果要修改已存在實現(xiàn)如绸,可以使用method_setImplementation嘱朽。一個Objective-C方法是一個簡單的C函數(shù),它至少包含兩個參數(shù)—self和_cmd竭沫。所以燥翅,我們的實現(xiàn)函數(shù)(IMP參數(shù)指向的函數(shù))至少需要兩個參數(shù),如下所示:
void myMethodIMP(
id self
,SEL _cmd
)
{
// implementation ....
}
獲取實例方法
Method class_getInstanceMethod ( Class cls, SEL name );
獲取類方法
Method class_getClassMethod ( Class cls, SEL name );
獲取所有方法的數(shù)組
Method * class_copyMethodList ( Class cls, unsigned int *outCount );
- class_getInstanceMethod蜕提、class_getClassMethod函數(shù)森书,與class_copyMethodList不同的是,這兩個函數(shù)都會去搜索父類的實現(xiàn)谎势。
- 返回包含所有實例方法的數(shù)組凛膏,如果需要獲取類方法,則可以使用class_copyMethodList(object_getClass(cls), &count)(一個類的實例方法是定義在元類里面)脏榆。該列表不包含父類實現(xiàn)的方法猖毫。outCount參數(shù)返回方法的個數(shù)。在獲取到列表后须喂,我們需要使用free()方法來釋放它吁断。
替代方法的實現(xiàn)
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
- 該函數(shù)的行為可以分為兩種:如果類中不存在name指定的方法趁蕊,則類似于class_addMethod函數(shù)一樣會添加方法;如果類中已存在name指定的方法仔役,則類似于method_setImplementation一樣替代原方法的實現(xiàn)掷伙。
返回方法的具體實現(xiàn)
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );
- 該函數(shù)在向類實例發(fā)送消息時會被調(diào)用,并返回一個指向方法實現(xiàn)函數(shù)的指針。這個函數(shù)會比method_getImplementation(class_getInstanceMethod(cls, name))更快。返回的函數(shù)指針可能是一個指向runtime內(nèi)部的函數(shù)法精,而不一定是方法的實際實現(xiàn)。例如宙地,如果類實例無法響應(yīng)selector,則返回的函數(shù)指針將是運行時消息轉(zhuǎn)發(fā)機制的一部分逆皮。
類實例是否響應(yīng)指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );
- 我們通常使用NSObject類的respondsToSelector:或instancesRespondToSelector:方法來達到相同目的宅粥。
協(xié)議(objc_protocol_list)
添加協(xié)議
BOOL class_addProtocol ( Class cls, Protocol *protocol );
返回類是否實現(xiàn)指定的協(xié)議
//可以使用NSObject類的conformsToProtocol:方法來替代。
BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );
返回類實現(xiàn)的協(xié)議列表
//返回的是一個數(shù)組电谣,在使用后我們需要使用free()手動釋放粹胯。
Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );
版本(version)
獲取版本號
int class_getVersion ( Class cls );
設(shè)置版本號
void class_setVersion ( Class cls, int version );
實例(Example)
//-----------------------------------------------------------
// MyClass.h
@interface MyClass : NSObject @property (nonatomic, strong) NSArray *array;
@property (nonatomic, copy) NSString *string;
- (void)method1;
- (void)method2;
+ (void)classMethod1;
@end
//-----------------------------------------------------------
// MyClass.m
#import "MyClass.h"
@interface MyClass () {
NSInteger _instance1;
NSString * _instance2;
}
@property (nonatomic, assign) NSUInteger integer;
- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2;
@end
@implementation MyClass
+ (void)classMethod1 {
}
- (void)method1 {
NSLog(@"call method method1");
}
- (void)method2 {
}
- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2 {
NSLog(@"arg1 : %ld, arg2 : %@", arg1, arg2);
}
@end
//-----------------------------------------------------------
// main.h
#import "MyClass.h"
#import "MySubClass.h"
#import int main(int argc, const char * argv[]) {
@autoreleasepool {
MyClass *myClass = [[MyClass alloc] init];
unsigned int outCount = 0;
Class cls = myClass.class;
// 類名
NSLog(@"class name: %s", class_getName(cls));
NSLog(@"==========================================================");
// 父類
NSLog(@"super class name: %s", class_getName(class_getSuperclass(cls)));
NSLog(@"==========================================================");
// 是否是元類
NSLog(@"MyClass is %@ a meta-class", (class_isMetaClass(cls) ? @"" : @"not"));
NSLog(@"==========================================================");
Class meta_class = objc_getMetaClass(class_getName(cls));
NSLog(@"%s's meta-class is %s", class_getName(cls), class_getName(meta_class));
NSLog(@"==========================================================");
// 變量實例大小
NSLog(@"instance size: %zu", class_getInstanceSize(cls));
NSLog(@"==========================================================");
// 成員變量
Ivar *ivars = class_copyIvarList(cls, &outCount);
for (int i = 0; i < outCount; i++) {
Ivar ivar = ivars[i];
NSLog(@"instance variable's name: %s at index: %d", ivar_getName(ivar), i);
}
free(ivars);
Ivar string = class_getInstanceVariable(cls, "_string");
if (string != NULL) {
NSLog(@"instace variable %s", ivar_getName(string));
}
NSLog(@"==========================================================");
// 屬性操作
objc_property_t * properties = class_copyPropertyList(cls, &outCount);
for (int i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSLog(@"property's name: %s", property_getName(property));
}
free(properties);
objc_property_t array = class_getProperty(cls, "array");
if (array != NULL) {
NSLog(@"property %s", property_getName(array));
}
NSLog(@"==========================================================");
// 方法操作
Method *methods = class_copyMethodList(cls, &outCount);
for (int i = 0; i < outCount; i++) {
Method method = methods[i];
NSLog(@"method's signature: %s", method_getName(method));
}
free(methods);
Method method1 = class_getInstanceMethod(cls, @selector(method1));
if (method1 != NULL) {
NSLog(@"method %s", method_getName(method1));
}
Method classMethod = class_getClassMethod(cls, @selector(classMethod1));
if (classMethod != NULL) {
NSLog(@"class method : %s", method_getName(classMethod));
}
NSLog(@"MyClass is%@ responsd to selector: method3WithArg1:arg2:", class_respondsToSelector(cls, @selector(method3WithArg1:arg2:)) ? @"" : @" not");
IMP imp = class_getMethodImplementation(cls, @selector(method1));
imp();
NSLog(@"==========================================================");
// 協(xié)議
Protocol * __unsafe_unretained * protocols = class_copyProtocolList(cls, &outCount);
Protocol * protocol;
for (int i = 0; i < outCount; i++) {
protocol = protocols[i];
NSLog(@"protocol name: %s", protocol_getName(protocol));
}
NSLog(@"MyClass is%@ responsed to protocol %s", class_conformsToProtocol(cls, protocol) ? @"" : @" not", protocol_getName(protocol));
NSLog(@"==========================================================");
}
return 0;
}
- 輸出結(jié)果
2014-10-22 19:41:37.452 RuntimeTest[3189:156810] class name: MyClass
2014-10-22 19:41:37.453 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] super class name: NSObject
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] MyClass is not a meta-class
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.454 RuntimeTest[3189:156810] MyClass's meta-class is MyClass
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance size: 48
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _instance1 at index: 0
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _instance2 at index: 1
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _array at index: 2
2014-10-22 19:41:37.455 RuntimeTest[3189:156810] instance variable's name: _string at index: 3
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] instance variable's name: _integer at index: 4
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] instace variable _string
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] property's name: array
2014-10-22 19:41:37.463 RuntimeTest[3189:156810] property's name: string
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] property's name: integer
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] property array
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method1
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method2
2014-10-22 19:41:37.464 RuntimeTest[3189:156810] method's signature: method3WithArg1:arg2:
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: integer
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setInteger:
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: array
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: string
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setString:
2014-10-22 19:41:37.465 RuntimeTest[3189:156810] method's signature: setArray:
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] method's signature: .cxx_destruct
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] method method1
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] class method : classMethod1
2014-10-22 19:41:37.466 RuntimeTest[3189:156810] MyClass is responsd to selector: method3WithArg1:arg2:
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] call method method1
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] ==========================================================
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] protocol name: NSCopying
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] protocol name: NSCoding
2014-10-22 19:41:37.467 RuntimeTest[3189:156810] MyClass is responsed to protocol NSCoding
2014-10-22 19:41:37.468 RuntimeTest[3189:156810] ==========================================================
動態(tài)創(chuàng)建類
創(chuàng)建一個新類和元類
Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes );
如果我們要創(chuàng)建一個根類,則superclass指定為Nil辰企。extraBytes通常指定為0,該參數(shù)是分配給類和元類對象尾部的索引ivars的字節(jié)數(shù)况鸣。
為了創(chuàng)建一個新類牢贸,我們需要調(diào)用objc_allocateClassPair。然后使用諸如class_addMethod镐捧,class_addIvar等函數(shù)來為新創(chuàng)建的類添加方法潜索、實例變量和屬性等。完成這些后懂酱,我們需要調(diào)用objc_registerClassPair函數(shù)來注冊類竹习,之后這個新類就可以在程序中使用了。
實例方法和實例變量應(yīng)該添加到類自身上列牺,而類方法應(yīng)該添加到類的元類上整陌。
銷毀一個類及其相關(guān)聯(lián)的類
void objc_disposeClassPair ( Class cls );
- 用于銷毀一個類,不過需要注意的是瞎领,如果程序運行中還存在類或其子類的實例泌辫,則不能調(diào)用針對類調(diào)用該方法。
在應(yīng)用中注冊由objc_allocateClassPair創(chuàng)建的類
void objc_registerClassPair ( Class cls );
實例(Example)
Class cls = objc_allocateClassPair(MyClass.class, "MySubClass", 0);
class_addMethod(cls, @selector(submethod1), (IMP)imp_submethod1, "v@:");
class_replaceMethod(cls, @selector(method1), (IMP)imp_submethod1, "v@:");
class_addIvar(cls, "_ivar1", sizeof(NSString *), log(sizeof(NSString *)), "i");
objc_property_attribute_t type = {"T", "@\"NSString\""};
objc_property_attribute_t ownership = { "C", "" };
objc_property_attribute_t backingivar = { "V", "_ivar1"};
objc_property_attribute_t attrs[] = {type, ownership, backingivar};
class_addProperty(cls, "property2", attrs, 3);
objc_registerClassPair(cls);
id instance = [[cls alloc] init];
[instance performSelector:@selector(submethod1)];
[instance performSelector:@selector(method1)];
- 輸出結(jié)果
2014-10-23 11:35:31.006 RuntimeTest[3800:66152] run sub method 1
2014-10-23 11:35:31.006 RuntimeTest[3800:66152] run sub method 1
動態(tài)創(chuàng)建對象
創(chuàng)建類實例
id class_createInstance ( Class cls, size_t extraBytes );
- 創(chuàng)建實例時九默,會在默認的內(nèi)存區(qū)域為類分配內(nèi)存震放。extraBytes參數(shù)表示分配的額外字節(jié)數(shù)。這些額外的字節(jié)可用于存儲在類定義中所定義的實例變量之外的實例變量驼修。該函數(shù)在ARC環(huán)境下無法使用殿遂。
調(diào)用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妨退。
在指定的位置(bytes)創(chuàng)建類實例
id objc_constructInstance ( Class cls, void *bytes );
銷毀類實例
void * objc_destructInstance ( id obj );
- 銷毀一個類的實例,但不會釋放并移除任何與其相關(guān)的引用
實例操作函數(shù)
實例操作函數(shù)主要是針對我們創(chuàng)建的實例對象的一系列操作函數(shù)蜕企,我們可以使用這組函數(shù)來從實例對象中獲取我們想要的一些信息咬荷,如實例對象中變量的值
返回指定對象的一份拷貝
id object_copy ( id obj, size_t size );
釋放指定對象占用的內(nèi)存
id object_dispose ( id obj );
- 有這樣一種場景,假設(shè)我們有類A和類B轻掩,且類B是類A的子類幸乒。類B通過添加一些額外的屬性來擴展類A。現(xiàn)在我們創(chuàng)建了一個A類的實例對象唇牧,并希望在運行時將這個對象轉(zhuǎn)換為B類的實例對象罕扎,這樣可以添加數(shù)據(jù)到B類的屬性中。這種情況下丐重,我們沒有辦法直接轉(zhuǎn)換腔召,因為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);
修改類實例的實例變量的值
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 );
設(shè)置對象中實例變量的值
void object_setIvar ( id obj, Ivar ivar, id value );
- 如果實例變量的Ivar已經(jīng)知道崖蜜,那么調(diào)用object_getIvar會比object_getInstanceVariable函數(shù)快浊仆,相同情況下,object_setIvar也比object_setInstanceVariable快
返回給定對象的類名
const char * object_getClassName ( id obj );
返回對象的類
Class object_getClass ( id obj );
設(shè)置對象的類
Class object_setClass ( id obj, Class cls );
獲取類定義
Objective-C動態(tài)運行庫會自動注冊我們代碼中定義的所有的類豫领。我們也可以在運行時創(chuàng)建類定義并使用objc_addClass函數(shù)來注冊它們抡柿。runtime提供了一系列函數(shù)來獲取類定義相關(guān)的信息
獲取已注冊的類定義的列表
int objc_getClassList ( Class *buffer, int bufferCount );
- objc_getClassList函數(shù):獲取已注冊的類定義的列表。我們不能假設(shè)從該函數(shù)中獲取的類對象是繼承自NSObject體系的等恐,所以在這些類上調(diào)用方法是洲劣,都應(yīng)該先檢測一下這個方法是否在這個類中實現(xiàn)。
創(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 );
- 如果指定的類沒有注冊鼠锈,則該函數(shù)會調(diào)用類處理回調(diào)闪檬,并再次確認類是否注冊,如果確認未注冊购笆,再返回nil粗悯。不過,每個類定義都必須有一個有效的元類定義同欠,所以這個函數(shù)總是會返回一個元類定義样傍,不管它是否有效横缔。
實例(Example)
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會調(diào)用類處理回調(diào),并再次確認類是否注冊撤逢,如果確認未注冊膛锭,再返回nil。而objc_getRequiredClass函數(shù)的操作與objc_getClass相同蚊荣,只不過如果沒有找到類初狰,則會殺死進程.