码迷,mamicode.com
首页 > 移动开发 > 详细

iOS RunTime运行时(1):类与对象

时间:2016-12-20 14:08:34      阅读:295      评论:0      收藏:0      [点我收藏+]

标签:方法   c++   执行   setvalue   select   _id   额外   32位   覆盖   

Objective-C语言是一门动态语言,他将很多静态语言在编译和链接期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码更具有灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一下方法的实现等。

这种特性意味着OC不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于OC来说,这个运行时系统就像一个操作系统一样:他让所有的工作可以正常的运行,这个运行时系统就是Objc RunTime。objc RunTime 其实是一个RunTime库,他基本上是用C语言和汇编写的。这个库使得C语言具有了面向对象的能力。

 

RunTime库主要做以下几件事:

1:封装:在这个库中 对象可以使用C语言中的结构体来表示,而方法可以用C函数来实现,另外再加上了一些额外的特性,这些结构体和函数被RunTime函数封装后,我们就可以在程序运行时创建 检查 修改类 对象和他们的方法了。

2:找出方法的最终执行代码  当程序执行[obj doSomething]时 会向消息接收者(obj)发送一条消息(doSomething) RunTime会根据接收消息者是否能响应此消息而做出不同反应。

 

OC RunTime有两个版本:Modern runtime 和 legacy runtime  Modern Runtime 覆盖了64位的Mac OS X Apps,还有 iOS Apps,Legacy Runtime 是早期用来给32位 Mac OS X Apps 用的,也就是可以不用管就是了。

 

在这一系列文章中,我们将介绍runtime的基本工作原理,以及如何利用它让我们的程序变得更加灵活。在本文中,我们先来介绍一下类与对象,这是面向对象的基础,我们看看在Runtime中,类是如何实现的。

类与对象基础数据结构

Class

Objective-C类是由Class类型来表示的 它实际上是一个指向objc_class结构体的指针 他的定义如下:

typedef struct objc_class *Class

查看objc/runtime.h 中objc_class结构体的定义如下:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

在这个几个定义中 下面几个字段是我们感兴趣的

1> isa: 需要注意的是在OC中 所有的类自身也是i一个对象 这个对象的Class里面 也有一个isa指针 它指向metaClass(元类) 我们会在后面介绍他。

2> super_class 指向该类的父类 如果该类已经是最顶层的根类(比如NSObject或者NSProxy) 则super_class为NULL

3> cache 用于缓存最近使用的方法,一个接收者接收到对象的时候 他会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的 很多方法实际上很少用到或者根本用不上。在这种情况下 如果每次来消息时 我们都是methodLists中遍历一遍 性能会很差。这个时候,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会缓存到cache中,下次调用的时候runtime会优先寻找cache 如果cache中没有,采取methodLists中去找 这样对于经常调用到的方法 就会提高很多效率。

4> version 我们可以使用这个字段来提供类的版本信息 这对于对象的序列化非常有用 它可是让我们识别出不同类定义版本中实例变量布局的改变。

针对cache 我们可以用下面的例子来说明其执行过程:

 

NSArray *array = [[NSArray alloc] init];

 

其流程是:

1.[NSArray alloc]先被执行。因为NSArray没有+alloc方法,于是去父类NSObject去查找。
2.检测NSObject是否响应+alloc方法,发现响应,于是检测NSArray类,并根据其所需的内存空间大小开始分配内存空间,然后把isa指针指向NSArray类。同时,+alloc也被加进cache列表里面。
3.接着,执行-init方法,如果NSArray响应该方法,则直接将其加入cache;如果不响应,则去父类查找。
4.在后期的操作中,如果再以[[NSArray alloc] init]这种方式来创建数组,则会直接从cache中取出相应的方法,直接调用。

objc_object 与 id

objc_object是表示一个类的实例的结构体,他的定义如下(objc/objc.h):

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;
#endif

可以看到,这个结构体中只有一个字体,即指向其类的isa指针。这样,当我们向一个Objective-C对象发送消息的时候,运行时库会根据实例对象的isa指针找到实例对象所属的类。RunTime库会在类的方法列表及父类的方法列表中寻找与消息对应的selector之乡的方法。找到后就运行这个方法。

当创建一个特定类的实例对象时 分配的内存包含一个objc_object数据结构,然后是类的实例变量的数据。在NSObject类的alloc 和 allocWithZone:方法是用函数class__createInstance来创建objc_object数据结构。

另外还有我们常见的id,它是一个objc_object结构类型的指针。它的存在可以让我们实现类似于C++中泛型的一些操作。该类型的对象可以转换为任何一种对象,有点类似于C语言中void *指针类型的作用。

objc_cache

上面提到了objc_class结构体中的cache字段,他用于缓存调用过的方法。这个字段是一个指向objc_cache结构体的指针。其定义如下:

struct objc_cache {
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
    unsigned int occupied                                    OBJC2_UNAVAILABLE;
    Method buckets[1]                                        OBJC2_UNAVAILABLE;
};

1:mask 一个整数,指定分配的缓存bucket的总数。在方法查找的过程中,Objective-C runtime使用这个字段来确定开始线性查找数组的索引位置。指向方法selector的指针与该字段做一个AND位操作(index=(mask & selector))这可以做一个简单的hash散列算法。

2.occupied 一个整数 指定实际占用的缓存bucket的总数

3.buckets:指向Method数据结构指针的数组。这个数组可能包含不超过mask+1个元素。需要注意的是,指针可能是NULL,表示这个缓存bucket没有被占用,另外被占用的bucket可能是不连续的。这个数组可能会随着时间而增长。

元类 (Meta Class)

在上面我们提到 所有类自身也是一个对象 我们可以向这个对象发送消息(调用类方法)

    
NSArray *array = [NSArray array];

这个例子中,+array消息发送给了NSArray类 而这个NSArray也是一个对象 既然是对象 那么他也是一个objc_object指针 包含一个指向其类的isa指针。那么 有这么一个疑问,这个isa指针指向了什么? 为了调用+array方法 这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体,这就引出了meta_class的概念。

meta-class是一个类对象的类。

当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。

meta-class之所以重要,是因为它存储着一个类的所有类方法。每个类都会有一个单独的meta-class,因为每个类的类方法基本不可能完全相同。

再深入一下,meta-class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的meta-class的isa指向基类的meta-class,以此作为它们的所属类。即,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而基类的meta-class的isa指针是指向它自己。这样就形成了一个完美的闭环。

通过上面的描述,再加上对objc_class结构体中super_class指针的分析,我们就可以描绘出类及相应meta-class类的一个继承体系了,如下图所示:

技术分享

对于NSObject继承体系来说,其实例方法对体系中的所有实例、类和meta-class都是有效的;而类方法对于体系内的所有类和meta-class都是有效的。


类与对象操作函数

runtime提供了大量的函数来操作类与对象。类的操作方法大部分是以class为前缀的,而对象的操作方法大部分是以objc或object_为前缀。下面我们将根据这些方法的用途来分类讨论这些方法的使用。

 

类相关的操作函数

我们可以回过头去看看objc_class的定义,runtime提供的操作类的方法主要就是针对这个结构体中的各个字段的。下面我们分别介绍这一些的函数。并在最后以实例来演示这些函数的具体用法。

 

类名(name)

类名的操作函数主要有:

const char *class_getName(Class cls) 

对于 class_getName(Class cls)函数 如果传入的cls为Nil 则返回一个nil。

父类(super_class)和元类(meta-class)

//获取父类名
Class  class_getSuperclass(Class cls)
//判断给定的class是不是一个元类
BOOL class_isMetaClass(Class cls)

class_getSuperclass函数,当cls为Nil或者cls为根类时,返回Nil。不过通常我们可以使用NSObject类的superclass方法来达到同样的目的。
class_isMetaClass函数,如果是cls是元类,则返回YES;如果否或者传入的cls为Nil,则返回NO。

示例代码:

#import "ViewController.h"
#import <objc/runtime.h>
#import "Person.h"


@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Person *p = [[Person alloc] init];
    //获取类名
    const char *className = class_getName([p class]);
    //变成oc中的String
    NSString *ocName = [NSString stringWithUTF8String:className];
    //获取父类的名称
    Class superClass = class_getSuperclass([p class]);
    const char *superName = class_getName(superClass);
    NSString *superOcName = [NSString stringWithUTF8String:superName];
    
    //判断是否为元类
    if (class_isMetaClass([p class])) {
        NSLog(@"我是元类");
    }else {
        NSLog(@"我不是元类");
    }
    
    NSLog(@"获取到的类名:%@ 它父类的名称是%@",ocName,superOcName);
    
}

打印结果:

2016-12-19 15:51:42.750 RunTimeDemo[1239:93957] 我不是元类
2016-12-19 15:51:42.752 RunTimeDemo[1239:93957] 获取到的类名:Person 它父类的名称是NSObject

 

实例变量的大小(instance_size)

    
// 获取实例大小
size_t class_getInstanceSize ( Class cls );

代码示例:

//获取实例变量的大小
    size_t size = class_getInstanceSize([p class]);
    NSLog(@"获取实例变量的大小%zu",size);
//结果
2016-12-19 15:59:20.350 RunTimeDemo[1257:96333] 获取实例变量的大小8

获取一个类的成员变量 主要使用一下函数

// 获取类中指定名称实例成员变量的信息
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 );

class_getInstanceVariable函数,他返回一个指向包含name指定的成员变量信息的objc_ivar结构体的指针(IVar)

class_getClassVariable函数,目前没有找到关于Objective-C中类变量的信息,一般认为Objective-C不支持类变量。注意,返回的列表不包含父类的成员变量和属性。

Objective-C不支持往已存在的类中添加实例变量,因此不管是系统库提供的提供的类,还是我们自定义的类,都无法动态添加成员变量。但如果我们通过运行时来创建一个类的话,又应该如何给它添加成员变量呢?这时我们就可以使用class_addIvar函数了。不过需要注意的是,这个方法只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。另外,这个类也不能是元类。成员变量的按字节最小对齐量是1<<alignment。这取决于ivar的类型和机器的架构。如果变量的类型是指针类型,则传递log2(sizeof(pointer_type))。

class_copyIvarList函数,它返回一个指向成员变量信息的数组,数组中每个元素是指向该成员变量信息的objc_ivar结构体的指针。这个数组不包含在父类中声明的变量。outCount指针返回数组的大小。需要注意的是,我们必须使用free()来释放这个数组。

示例代码:

- (void)getClassIvarDemo {
    UInt32 count;
    //动态获取某个类中的成员变量
    Ivar *ivars = class_copyIvarList([Person class], &count);
    //遍历属性 列表
    for (UInt32 i = 0; i < count; i ++) {
        Ivar ivar = ivars[i];
        
        const char *ivarName = ivar_getName(ivar);
        NSString *ocName = [NSString stringWithUTF8String:ivarName];
        //获取成员变量的类型
        const char * typeName = ivar_getTypeEncoding(ivar);
        NSLog(@"成员变量:%@ 成员变量的类型%@",ocName,[NSString stringWithUTF8String:typeName]);
    }
    free(ivars);
    Person *p = [[Person alloc] init];
    p.name = @"tian";
    //获取Person类中一个指定的类的信息
    Ivar ivar = class_getInstanceVariable([Person class], "_name");
    //获取该属性的值
    id name = object_getIvar(p, ivar);
    NSString *newName = @"wang";
    if ( name != newName) {
        //为成员变量赋值
        object_setIvar(p, ivar, newName);
    }
    
    NSLog(@"%@ 成员变量新值%@",[NSString stringWithUTF8String:ivar_getName(ivar)],p.name);
    
}

结果:
2016-12-19 17:07:10.333 RunTimeDemo[1437:122637] 成员变量:_age 成员变量的类型i
2016-12-19 17:07:10.334 RunTimeDemo[1437:122637] 成员变量:_name 成员变量的类型@"NSString"
2016-12-19 17:07:10.334 RunTimeDemo[1437:122637] 成员变量:_ID 成员变量的类型@"NSString"
2016-12-19 17:07:10.334 RunTimeDemo[1437:122637] _name 成员变量新

添加成员变量 将在会面的章节介绍。

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 );

示例代码:

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    NSString *weight;
}

@property (nonatomic,copy) NSString *name;

@property (nonatomic,assign) int age;

@property (nonatomic,copy) NSString *ID;

@end


- (void)getClassPropertyListDemo {
    uint count;
    
    //获取属性列表
    objc_property_t *propertys = class_copyPropertyList([Person class], &count);
    for (uint i = 0; i < count; i ++) {
        objc_property_t property = propertys[i];
        //属性的名字
        const char * propertyName = property_getName(property);
        //属性名称
        NSString *ocName = [NSString stringWithUTF8String:propertyName];
        
        //获取属性的类型
        const char *propertyType = property_getAttributes(property);
        NSString *ocType = [NSString stringWithUTF8String:propertyType];
        
        NSLog(@"属性的名字%@ ----- 属性的属性%@",ocName,ocType);
    }
    free(propertys);
    
    Person *p = [[Person alloc] init];
    p.name = @"tianlianfeng";
    //获取特定的属性
    objc_property_t property = class_getProperty([Person class], "name");
    //获取特定属性的值
    [p setValue:@"tianxiaoer" forKey:[NSString stringWithUTF8String: property_getName(property)]];
    NSLog(@"属性的值%@",p.name);
}

结果:
2016-12-19 17:42:10.847 RunTimeDemo[1520:134330] 属性的名字name ----- 属性的属性T@"NSString",C,N,V_name
2016-12-19 17:42:10.848 RunTimeDemo[1520:134330] 属性的名字age ----- 属性的属性Ti,N,V_age
2016-12-19 17:42:10.848 RunTimeDemo[1520:134330] 属性的名字ID ----- 属性的属性T@"NSString",C,N,V_ID
2016-12-19 17:42:10.849 RunTimeDemo[1520:134330] 属性的值tianxiaoer

可以看到打印的属性 并没有 weight 因为weight没有被 @property修饰。

方法(methodLists)

在讲方法前 我们需要了解一些东西。

首先看一下方法的定义 Method 就是一个objc_method结构体

objc_method是类的一个方法的描述。

定义如下:

typedef struct objc_method *Method;  
  
struct objc_method {  
    SEL method_name;        // 方法名称  
    charchar *method_typesE;    // 参数和返回类型的描述字串  
    IMP method_imp;         // 方法的具体的实现的指针  
}  

那么方法的实现主要有以下函数:

// 添加方法
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 );

代码示例:

先看一下 为了实验配置的Person类

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    NSString *weight;
}

@property (nonatomic,copy) NSString *name;

@property (nonatomic,assign) int age;

@property (nonatomic,copy) NSString *ID;


- (void)method1;

- (void)method2;

+ (void)classMethod;

@end


#import "Person.h"

@interface Person ()

- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2;

@end

@implementation Person



- (void)method1 {
    NSLog(@"我是method1的实现");
}


-(void)method2 {
    NSLog(@"我是method2的实现");
}

+ (void)classMethod {
    NSLog(@"我是类方法");
}

- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2 {
    NSLog(@"arg1 : %ld, arg2 : %@", arg1, arg2);
}

@end

 

//获取一个类中的所有方法列表
- (void) getClassMethodList {
    uint outCount;
    //获取所有的方法  但是不知道为什么 类方法 没有打印出来
    
    Method *methods = class_copyMethodList([Person class], &outCount);
    for (uint i = 0; i < outCount; i ++) {
        Method method = methods[i];
        //获取方法的名字
        SEL selector = method_getName(method);
        
        NSLog(@"%@",NSStringFromSelector(selector));
    }
    free(methods);
    
}

//获取类中的指定方法

- (void)getClassMethod {
    //获取类中指定的实例方法
    Method method = class_getInstanceMethod([Person class], @selector(method1));
    
    if (method) {
        //获取该方法的实现指针
        IMP imp = class_getMethodImplementation([Person class], @selector(method1));
        NSLog(@"方法的实现指针%p",imp);
    }
    
    //获取类中指定的类方法
    Method classMethod = class_getClassMethod([Person class], @selector(classMethod));
    if (classMethod) {
        //获取该方法的实现指针
        IMP imp = class_getMethodImplementation_stret([Person class], @selector(classMethod));
        NSLog(@"方法的实现指针%p",imp);
    }
    
}

替代方法的实现 好像实例方法不能喝类方法交换 试了两次 程序运行崩溃

- (void)getClassMethod {
    //获取类中指定的实例方法
    Method method = class_getInstanceMethod([Person class], @selector(method1));
    //获取该方法的实现指针
    IMP imp = class_getMethodImplementation([Person class], @selector(method1));
    Method method2 = class_getInstanceMethod([Person class], @selector(method2));
    //方法二的实现指针
    IMP method2Imp = class_getMethodImplementation([Person class], @selector(method2));
    
    //交换方法的实现 方法一
    
    //替代方法的实现 将方法一的实现 改为方法二的实现 现在调用方法一 实现的是方法二
    class_replaceMethod([Person class], @selector(method1), method2Imp, method_getTypeEncoding(method2));
    //将method2 方法的实现指针 指向 method1 调用method2实现的是method1
    class_replaceMethod([Person class], @selector(method2), imp, method_getTypeEncoding(method));
    
    Person *p = [[Person alloc] init];
    [p method1];
    //执行结果:我是method2的实现
    [p method2];
    //执行结果:我是method1的实现
    
    //交换方法的实现 方法二
    method_exchangeImplementations(method, method2);
    
    //交换方法的实现 方法三
    method_setImplementation(method, method2Imp);
    method_setImplementation(method2, imp);
    
    [p method1];
    //执行结果:我是method2的实现
    [p method2];
    //执行结果:我是method1的实现
}

通常来讲 交换或者拦截系统的方法 是我们关心的 因为交换我们自己写的方法 其实没什么意义。

 

- (void)method3 {
    NSLog(@"我是方法三");
    //拦截了系统方法 但是我们又想让他响应
    [self method3];
}

- (void)addMethodForSelf {
    //获取方法
    Method viewwill = class_getInstanceMethod([self class], @selector(viewWillAppear:));
    Method method = class_getInstanceMethod([self class], @selector(method3));
    BOOL success = class_addMethod([self class], @selector(viewWillAppear:), class_getMethodImplementation([self class], @selector(method3)), method_getTypeEncoding(method))
    ;
    if (success) {
        class_replaceMethod([self class],@selector(method3) , class_getMethodImplementation([self class], @selector(viewWillAppear:)),method_getTypeEncoding(viewwill));
    }else {
        method_exchangeImplementations(viewwill, method);
    }

    
}

交换方法有几种途径 周全起见,有两种情况要考虑一下。第一种情况是要复写的方法(overridden)并没有在目标类中实现(notimplemented),而是在其父类中实现了。第二种情况是这个方法已经存在于目标类中(does existin the class itself)。这两种情况要区别对待。 (译注: 这个地方有点要明确一下,它的目的是为了使用一个重写的方法替换掉原来的方法。但重写的方法可能是在父类中重写的,也可能是在子类中重写的。) 对于第一种情况,应当先在目标类增加一个新的实现方法(override),然后将复写的方法替换为原先(的实现(original one)。 对于第二情况(在目标类重写的方法)。这时可以通过method_exchangeImplementations来完成交换

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:方法来达到相同目的。

协议(objc_protocol_list)

协议相关的操作包含以下函数:

// 添加协议
BOOL class_addProtocol ( Class cls, Protocol *protocol );
 
// 返回类是否实现指定的协议
BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );
 
// 返回类实现的协议列表
Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );

示例代码

 // 协议
        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));
 

参考博客:http://blog.jobbole.com/79566/

iOS RunTime运行时(1):类与对象

标签:方法   c++   执行   setvalue   select   _id   额外   32位   覆盖   

原文地址:http://www.cnblogs.com/huanying2000/p/6198443.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!