runtime是oc实现动态语言的底层机制,使用的时候只要引入#import <objc/runtime.h>即可。 runtime提供了大量的函数来操作类和对象,一般操作类的方法都以class_开头,操作对象的方法以objc_或object_开头。 1.runtime可以动态创建一个类,动态创建类涉及到以下几个函数: // 创建一个新类和元类 Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes ); // 销毁一个类及其相关联的类 void objc_disposeClassPair ( Class cls ); // 在应用中注册由objc_allocateClassPair创建的类 void objc_registerClassPair ( Class cls ); 具体方法如下: 模版: Class 你的类 = objc_allocateClassPair([你的类的父类 class], "你的类名", 0); class_addMethod(你的类, @selector(提供外部调用的方法名称,直接写即可,不用写字符串), (IMP)关联内部的c函数, "标识符,随便写"); objc_registerClassPair(你的类); 例: Class aClass = objc_allocateClassPair([NSArray class], "ABC", 0); class_addMethod(aClass, @selector(ttt2TTT), (IMP)tttTTT, "ssssssffffff"); objc_registerClassPair(aClass); 该类所关联的函数要这样写: 模版: void 关联内部的c函数(id 类的实例self, SEL 方法名) { } 例: void tttTTT(id self, SEL _cmd) { //self是类的实例self,_cmd是调用的方法名 } 调用方法时这样调用: 模版: id 实例 = [[你的类 alloc] init]; [实例 performSelector:@selector(外部调用的方法名)]; 例: id aObj = [[aClass alloc] init]; [aObj performSelector:@selector(ttt2TTT)]; 另外还可以调用如下方法来添加方法和变量 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); 2.动态创建对象 动态创建对象的函数如下: // 创建类实例 id class_createInstance ( Class cls, size_t extraBytes ); // 在指定位置创建类实例 id objc_constructInstance ( Class cls, void *bytes ); // 销毁类实例 void * objc_destructInstance ( id obj ); 方法如下: //runtime创建对象 id theObject = class_createInstance(NSString.class, sizeof(unsigned)); id str1 = [theObject init]; NSLog(@"%@", [str1 class]); //普通创建对象 id str2 = [[NSString alloc] initWithString:@"test"]; NSLog(@"%@", [str2 class]); 3.将a类转化为b类 NSObject *a = [[NSObject alloc] init]; id newB = object_copy(a, class_getInstanceSize(MyClass.class)); object_setClass(newB, MyClass.class); object_dispose(a); ***操作函数 #类名 //获取类的类名 const char * class_getName ( Class cls ); #父类和元类 // 获取类的父类 Class class_getSuperclass ( Class cls ); // 判断给定的Class是否是一个元类 BOOL class_isMetaClass ( Class cls ); #实例变量大小 // 获取实例大小 size_t class_getInstanceSize ( Class cls ); #成员变量(ivars)及属性 #1.成员变量操作函数,主要包含以下函数 // 获取类中指定名称实例成员变量的信息 Ivar class_getInstanceVariable ( Class cls, const char *name ); // 获取类成员变量的信息 Ivar class_getClassVariable ( Class cls, const char *name ); // 添加成员变量 BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types ); // 获取整个成员变量列表 Ivar * class_copyIvarList ( Class cls, unsigned int *outCount ); #2.属性操作函数,主要包含以下函数 // 获取指定的属性 objc_property_t class_getProperty ( Class cls, const char *name ); // 获取属性列表 objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount ); // 为类添加属性 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 ); 3.runtime提供了几个函数来确定一个对象的内存区域是否可以被垃圾回收器扫描,以处理strong/weak引用 const uint8_t * class_getIvarLayout ( Class cls ); void class_setIvarLayout ( Class cls, const uint8_t *layout ); const uint8_t * class_getWeakIvarLayout ( Class cls ); void class_setWeakIvarLayout ( Class cls, const uint8_t *layout ); //但通常情况下,我们不需要去主动调用这些方法 #方法操作 // 添加方法 BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types ); // 获取实例方法 Method class_getInstanceMethod ( Class cls, SEL name ); // 获取类方法 Method class_getClassMethod ( Class cls, SEL name ); // 获取所有方法的数组 Method * class_copyMethodList ( Class cls, unsigned int *outCount ); // 替代方法的实现 IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types ); // 返回方法的具体实现 IMP class_getMethodImplementation ( Class cls, SEL name ); IMP class_getMethodImplementation_stret ( Class cls, SEL name ); // 类实例是否响应指定的selector BOOL class_respondsToSelector ( Class cls, SEL sel ); class_addMethod的实现会覆盖父类的方法实现,但不会取代本类中已存在的实现,如果本类中包含一个同名的实现,则函数会返回NO。 与成员变量不同的是,我们可以为类动态添加方法,不管这个类是否已存在。 如果要修改已存在实现,可以使用method_setImplementation。一个Objective-C方法是一个简单的C函数,它至少包含两个参数—self和_cmd。 所以,我们的实现函数(IMP参数指向的函数)至少需要两个参数: void myMethodIMP(id self, SEL _cmd) { //方法实现 } class_getInstanceMethod、class_getClassMethod函数,与class_copyMethodList不同的是,这两个函数都会去搜索父类的实现。 class_copyMethodList函数,返回包含所有实例方法的数组,如果需要获取类方法,则可以使用class_copyMethodList(object_getClass(cls), &count)(一个类的实例方法是定义在元类里面)。该列表不包含父类实现的方法。outCount参数返回方法的个数。在获取到列表后,我们需要使用free()方法来释放它。 class_replaceMethod函数,该函数的行为可以分为两种:如果类中不存在name指定的方法,则类似于class_addMethod函数一样会添加方法;如果类中已存在name指定的方法,则类似于method_setImplementation一样替代原方法的实现。 class_getMethodImplementation函数,该函数在向类实例发送消息时会被调用,并返回一个指向方法实现函数的指针。这个函数会比method_getImplementation(class_getInstanceMethod(cls, name))更快。返回的函数指针可能是一个指向runtime内部的函数,而不一定是方法的实际实现。例如,如果类实例无法响应selector,则返回的函数指针将是运行时消息转发机制的一部分。 class_respondsToSelector函数,我们通常使用NSObject类的respondsToSelector:或instancesRespondToSelector:方法来达到相同目的 #协议操作 // 添加协议 BOOL class_addProtocol ( Class cls, Protocol *protocol ); // 返回类是否实现指定的协议 BOOL class_conformsToProtocol ( Class cls, Protocol *protocol ); // 返回类实现的协议列表 Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount ); class_conformsToProtocol函数可以使用NSObject类的conformsToProtocol:方法来替代。 class_copyProtocolList函数返回的是一个数组,在使用后我们需要使用free()手动释放。 #版本操作 // 获取版本号 int class_getVersion ( Class cls ); // 设置版本号 void class_setVersion ( Class cls, int version ); #其它 runtime还提供了两个函数来供CoreFoundation的tool-free bridging使用。 Class objc_getFutureClass ( const char *name ); void objc_setFutureClass ( Class cls, const char *name ); #实例操作函数 #针对整个对象进行操作的函数,这类函数包含 // 返回指定对象的一份拷贝 id object_copy ( id obj, size_t size ); // 释放指定对象占用的内存 id object_dispose ( id obj ); #针对对象实例变量进行操作的函数,这类函数包含 // 修改类实例的实例变量的值 Ivar object_setInstanceVariable ( id obj, const char *name, void *value ); // 获取对象实例变量的值 Ivar object_getInstanceVariable ( id obj, const char *name, void **outValue ); // 返回指向给定对象分配的任何额外字节的指针 void * object_getIndexedIvars ( id obj ); // 返回对象中实例变量的值 id object_getIvar ( id obj, Ivar ivar ); // 设置对象中实例变量的值 void object_setIvar ( id obj, Ivar ivar, id value ); #针对对象的类进行操作的函数,这类函数包含 // 返回给定对象的类名 const char * object_getClassName ( id obj ); // 返回对象的类 Class object_getClass ( id obj ); // 设置对象的类 Class object_setClass ( id obj, Class cls ); #获取类定义 Objective-C动态运行库会自动注册我们代码中定义的所有的类。 我们也可以在运行时创建类定义并使用objc_addClass函数来注册它们。 runtime提供了一系列函数来获取类定义相关的信息,这些函数主要包括: // 获取已注册的类定义的列表 int objc_getClassList ( Class *buffer, int bufferCount ); // 创建并返回一个指向所有已注册类的指针列表 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 ); 例: 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); } 获取类定义的方法有三个:objc_lookUpClass, objc_getClass和objc_getRequiredClass。 如果类在运行时未注册,则objc_lookUpClass会返回nil,而objc_getClass会调用类处理回调, 并再次确认类是否注册,如果确认未注册,再返回nil。 而objc_getRequiredClass函数的操作与objc_getClass相同, 只不过如果没有找到类,则会杀死进程。
[iOS]runtime笔记
最新推荐文章于 2025-01-08 16:59:21 发布