方法集
Runtime
  类相关
    通用
      获取类名
        const char * class_getName ( Class cls );
      获取类的父类
        Class class_getSuperclass ( Class cls );
      判断是否是元类
        BOOL class_isMetaClass ( Class cls );
      获取实例大小
        size_t class_getInstanceSize ( Class cls );
    成员(ivars)和属性(property)
      成员(ivars)
        获取类中指定名称实例成员变量的信息
          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 );
      属性(property)
        获取指定的属性
          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 );
      垃圾回收器
        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 );
    协议
      添加协议
        BOOL class_addProtocol ( Class cls, Protocol *protocol );
      返回类是否实现指定的协议
        BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );
      返回类实现的协议列表
        Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );
    版本(version)
      获取版本号
        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 );
    实例
      //-----------------------------------------------------------
// MyClass.h
@interface MyClass : NSObject <NSCopying, NSCoding>
@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 <objc/runtime.h>
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(@"==========================================================");
// 协议
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;
}
  对象相关
    动态创建类
      创建一个新类和元类
        Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes );
      在应用中注册由objc_allocateClassPair创建的类
        void objc_registerClassPair ( Class cls );
      销毁一个类及其相关联的类
        void objc_disposeClassPair ( Class cls );
      实例
        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)];
    动态创建对象
      创建类实例
        id class_createInstance ( Class cls, size_t extraBytes );
      在指定位置创建类实例
        id objc_constructInstance ( Class cls, void *bytes );
      销毁类实例
        void * objc_destructInstance ( id obj );
    实例操作函数
      针对整个对象
        返回指定对象的一份拷贝
          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 );
    获取类定义
      获取已注册的类定义的列表
        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_ASSOCIATION_ASSIGN
OBJC_ASSOCIATION_RETAIN_NONATOMIC
OBJC_ASSOCIATION_COPY_NONATOMIC
OBJC_ASSOCIATION_RETAIN
OBJC_ASSOCIATION_COPY
      连接关联对象
        static char myKey;
objc_setAssociatedObject(self, &myKey, anObject, OBJC_ASSOCIATION_RETAIN);
      获取关联对象
        id anObject = objc_getAssociatedObject(self, &myKey);
      删除关联对象
        objc_removeAssociatedObjects(self);
  方法(Method)
    方法
      调用指定方法的实现
        id method_invoke ( id receiver, Method m, ... );
      调用返回一个数据结构的方法的实现
        void method_invoke_stret ( id receiver, Method m, ... );
      获取方法名
        SEL method_getName ( Method m );
      返回方法的实现
        IMP method_getImplementation ( Method m );
      获取描述方法参数和返回值类型的字符串
        const char * method_getTypeEncoding ( Method m );
      获取方法的返回值类型的字符串
        char * method_copyReturnType ( Method m );
      获取方法的指定位置参数的类型字符串
        char * method_copyArgumentType ( Method m, unsigned int index );
      通过引用返回方法的返回值类型字符串
        void method_getReturnType ( Method m, char *dst, size_t dst_len );
      返回方法的参数的个数
        unsigned int method_getNumberOfArguments ( Method m );
      通过引用返回方法指定位置参数的类型字符串
        void method_getArgumentType ( Method m, unsigned int index, char *dst, size_t dst_len );
      返回指定方法的方法描述结构体
        struct objc_method_description * method_getDescription ( Method m );
      设置方法的实现
        IMP method_setImplementation ( Method m, IMP imp );
      交换两个方法的实现
        void method_exchangeImplementations ( Method m1, Method m2 );
    方法选择器
      返回给定选择器指定的方法的名称
        const char * sel_getName ( SEL sel );
      注册一个方法，将方法名映射到一个选择器，并返回这个选择器
        SEL sel_registerName ( const char *str );
      根据id获取选择器
        SEL sel_getUid ( const char *str );
      比较两个选择器
        BOOL sel_isEqual ( SEL lhs, SEL rhs );
  成员(Ivar)和属性(Property)
    成员(Ivar)
      获取成员变量名
        const char * ivar_getName ( Ivar v );
      获取成员变量类型编码
        const char * ivar_getTypeEncoding ( Ivar v );
      获取成员变量的偏移量
        ptrdiff_t ivar_getOffset ( Ivar v );
    属性(Property)
      获取属性名
        const char * property_getName ( objc_property_t property );
      获取属性特性描述字符串
        const char * property_getAttributes ( objc_property_t property );
      获取属性中指定的特性
        char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );
      获取属性的特性列表
        objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount );
  协议
    返回指定的协议
      Protocol * objc_getProtocol ( const char *name );
    获取运行时所知道的所有协议的数组
      Protocol ** objc_copyProtocolList ( unsigned int *outCount );
    创建新的协议实例
      Protocol * objc_allocateProtocol ( const char *name );
    在运行时中注册新创建的协议
      void objc_registerProtocol ( Protocol *proto );
    为协议添加方法
      void protocol_addMethodDescription ( Protocol *proto, SEL name, const char *types, BOOL isRequiredMethod, BOOL isInstanceMethod );
    添加一个已注册的协议到协议中
      void protocol_addProtocol ( Protocol *proto, Protocol *addition );
    为协议添加属性
      void protocol_addProperty ( Protocol *proto, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount, BOOL isRequiredProperty, BOOL isInstanceProperty );
    返回协议名
      const char * protocol_getName ( Protocol *p );
    判断两个协议是否相等
      BOOL protocol_isEqual ( Protocol *proto, Protocol *other );
    获取协议中指定条件的方法的方法描述数组
      struct objc_method_description * protocol_copyMethodDescriptionList ( Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount );
    获取协议中指定方法的方法描述
      struct objc_method_description protocol_getMethodDescription ( Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod );
    获取协议中的属性列表
      objc_property_t * protocol_copyPropertyList ( Protocol *proto, unsigned int *outCount );
    获取协议的指定属性
      objc_property_t protocol_getProperty ( Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty );
    获取协议采用的协议
      Protocol ** protocol_copyProtocolList ( Protocol *proto, unsigned int *outCount );
    查看协议是否采用了另一个协议
      BOOL protocol_conformsToProtocol ( Protocol *proto, Protocol *other );
  类型编码
类的操作方法大部分是以class为前缀的，而对象的操作方法大部分是以objc或object_为前缀。
目前没有找到关于Objective-C中类变量的信息
Objective-C不支持往已存在的类中添加实例变量，因此不管是系统库提供的提供的类，还是我们自定义的类，都无法动态添加成员变量。但如果我们通过运行时来创建一个类的话，又应该如何给它添加成员变量呢？这时我们就可以使用class_addIvar函数了。不过需要注意的是，这个方法只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。另外，这个类也不能是元类。成员变量的按字节最小对齐量是1<<alignment。这取决于ivar的类型和机器的架构。如果变量的类型是指针类型，则传递log2(sizeof(pointer_type))。
class_copyIvarList函数，它返回一个指向成员变量信息的数组，数组中每个元素是指向该成员变量信息的objc_ivar结构体的指针。这个数组不包含在父类中声明的变量。outCount指针返回数组的大小。需要注意的是，我们必须使用free()来释放这个数组。
在MAC OS X系统中，我们可以使用垃圾回收器。runtime提供了几个函数来确定一个对象的内存区域是否可以被垃圾回收器扫描，以处理strong/weak引用。但通常情况下，我们不需要去主动调用这些方法；在调用objc_registerClassPair时，会生成合理的布局。
class_addMethod的实现会覆盖父类的方法实现，但不会取代本类中已存在的实现，如果本类中包含一个同名的实现，则函数会返回NO。如果要修改已存在实现，可以使用method_setImplementation。一个Objective-C方法是一个简单的C函数，它至少包含两个参数—self和_cmd。所以，我们的实现函数(IMP参数指向的函数)至少需要两个参数，如下所示：
void myMethodIMP(id self, SEL _cmd)
{
// implementation ....
}
与成员变量不同的是，我们可以为类动态添加方法，不管这个类是否已存在。
另外，参数types是一个描述传递给方法的参数类型的字符数组，这就涉及到类型编码。
会去搜索父类。
会去搜索父类。
该列表不包含父类实现的方法。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:方法来达到相同目的。
class_conformsToProtocol函数可以使用NSObject类的conformsToProtocol:方法来替代。
class_copyProtocolList函数返回的是一个数组，在使用后我们需要使用free()手动释放。
objc_allocateClassPair函数：如果我们要创建一个根类，则superclass指定为Nil。extraBytes通常指定为0，该参数是分配给类和元类对象尾部的索引ivars的字节数。
为了创建一个新类，我们需要调用objc_allocateClassPair。然后使用诸如class_addMethod，class_addIvar等函数来为新创建的类添加方法、实例变量和属性等。完成这些后，我们需要调用objc_registerClassPair函数来注册类，之后这个新类就可以在程序中使用了。
实例方法和实例变量应该添加到类自身上，而类方法应该添加到类的元类上。
objc_disposeClassPair函数用于销毁一个类，不过需要注意的是，如果程序运行中还存在类或其子类的实例，则不能调用针对类调用该方法。
class_createInstance函数：创建实例时，会在默认的内存区域为类分配内存。extraBytes参数表示分配的额外字节数。这些额外的字节可用于存储在类定义中所定义的实例变量之外的实例变量。该函数在ARC环境下无法使用。
调用class_createInstance的效果与+alloc方法类似。不过在使用class_createInstance时，我们需要确切的知道我们要用它来做什么。在下面的例子中，我们用NSString来测试一下该函数的实际效果：
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函数获取的是NSString实例，而不是类簇中的默认占位符类__NSCFConstantString。
实例操作函数主要是针对我们创建的实例对象的一系列操作函数，我们可以使用这组函数来从实例对象中获取我们想要的一些信息，如实例对象中变量的值。
有这样一种场景，假设我们有类A和类B，且类B是类A的子类。类B通过添加一些额外的属性来扩展类A。现在我们创建了一个A类的实例对象，并希望在运行时将这个对象转换为B类的实例对象，这样可以添加数据到B类的属性中。这种情况下，我们没有办法直接转换，因为B类的实例会比A类的实例更大，没有足够的空间来放置对象。此时，我们就要以使用以上几个函数来处理这种情况，如下代码所示：
NSObject *a = [[NSObject alloc] init];
id newB = object_copy(a, class_getInstanceSize(MyClass.class));
object_setClass(newB, MyClass.class);
object_dispose(a);
Objective-C动态运行库会自动注册我们代码中定义的所有的类。我们也可以在运行时创建类定义并使用objc_addClass函数来注册它们。runtime提供了一系列函数来获取类定义相关的信息
获取类定义的方法有三个：objc_lookUpClass, objc_getClass和objc_getRequiredClass。如果类在运行时未注册，则objc_lookUpClass会返回nil，而objc_getClass会调用类处理回调，并再次确认类是否注册，如果确认未注册，再返回nil。而objc_getRequiredClass函数的操作与objc_getClass相同，只不过如果没有找到类，则会杀死进程。
objc_getMetaClass函数：如果指定的类没有注册，则该函数会调用类处理回调，并再次确认类是否注册，如果确认未注册，再返回nil。不过，每个类定义都必须有一个有效的元类定义，所以这个函数总是会返回一个元类定义，不管它是否有效。
我们可以把关联对象想象成一个Objective-C对象(如字典)，这个对象通过给定的key连接到类的一个实例上。不过由于使用的是C接口，所以key是一个void指针(const void *)。
当宿主对象被释放时，会根据指定的内存管理策略来处理关联对象。
ivar_getOffset函数，对于类型id或其它对象类型的实例变量，可以调用object_getIvar和object_setIvar来直接访问成员变量，而不使用偏移量。
返回值在使用完后需要调用free()释放。
返回值在使用完后需要调用free()释放。
作为对Runtime的补充，编译器将每个方法的返回值和参数类型编码为一个字符串，并将其与方法的selector关联在一起。这种编码方案在其它情况下也是非常有用的，因此我们可以使用@encode编译器指令来获取它。当给定一个类型时，@encode返回这个类型的字符串编码。这些类型可以是诸如int、指针这样的基本类型，也可以是结构体、类等类型。事实上，任何可以作为sizeof()操作参数的类型都可以用于@encode()。
如以下示例：
float a[] = {1.0, 2.0, 3.0};
NSLog(@"array encoding type: %s", @encode(typeof(a)));
输出是：
2014-10-28 11:44:54.731 RuntimeTest[942:50791] array encoding type: [3f]