runtime 由浅入深

把runtime的内容由浅入深分几篇博客记录下来,希望能与大家共同探讨。

1,消息传递:messaging

可以看苹果定义的一些相关结构体,从而了解方法调用的内部原理。(越来越觉得还是看英文顺眼~)

objc/objc.h

/// An opaque type that represents an Objective-C class.

typedef struct objc_class *Class;


/// Represents an instance of a class.

struct objc_object {

    Class isa  OBJC_ISA_AVAILABILITY;

};


/// A pointer to an instance of a class.

typedef struct objc_object *id;

#endif


/// An opaque type that represents a method selector.

typedef struct objc_selector *SEL;


/// A pointer to the function of a method implementation. 

#if !OBJC_OLD_DISPATCH_PROTOTYPES

typedef void (*IMP)(void /* id, SEL, ... */ ); 

#else

typedef id (*IMP)(id, SEL, ...); 

#endif


runtime.h

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;


struct objc_method {

    SEL method_name                                          OBJC2_UNAVAILABLE;

    char *method_types                                       OBJC2_UNAVAILABLE;

    IMP method_imp                                           OBJC2_UNAVAILABLE;

}

struct objc_method_list {

    struct objc_method_list *obsolete                        OBJC2_UNAVAILABLE;


    int method_count                                         OBJC2_UNAVAILABLE;

#ifdef __LP64__

    int space                                                OBJC2_UNAVAILABLE;

#endif

    /* variable length structure */

    struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;

}            


发送消息时,在编译时候会转为c函数的调用:objc_msgSend
obj:实例 ; foo:方法名
例如 :objc_msgSend(obj,foo)
调用过程:
1.通过obj的isa指针找到obj所属的class.
2.在class的methodLists找foo
3.如果 methodLists中没有foo,通过class的super_class指针找class的superclass中的methodLists
4.一旦找到foo这个函数,就去执行它的视线IMP.
为了提高查找方法的效率,objc_cache会把经常调用的函数缓存起来,例如找到foo函数时候,把foo的method_name作为key,method_imp作为value存起来。

2,动态方法解析和转发
如果上述调用过程中,没有找到foo函数的实现(IMP),通常程序会抛出异常:unrecognized selector sent to...,于是,runtime提供了一些方法,可以在抛出异常之前,实现一些方法以避免。
1.method resolution
首先runtime会调用+resolveInstanceMethod:(调用实例方法)或+resolveClassMethod:(调用类方法)。
我们便有机会提供一个函数实现。如果添加了该函数给个实现,最后返回YES,runtime就会重新启动一次消息发送的过程,那么这次,就会找到你添加的那个实现,并执行。
例子:定义一个类如下
.h

#import <Foundation/Foundation.h>

@interface RuntimeObject : NSObject

//- (void)runtimeTest;

@end

.m

#import "RuntimeObject.h"

#import <objc/runtime.h>

#import <objc/message.h>

@implementation RuntimeObject


//添加了一个c函数

void addedTheRuntimeTestMethod(id obj, SEL _cmd) {

    NSLog(@"addedTheRuntimeTestMethod execute !");

}

+ (BOOL)resolveInstanceMethod:(SEL)sel{

    if (sel == @selector(runtimeTest)) {

        //可以重写父类的方法,但是本类的方法如果想改变IMP,使用method_setImplementation

        class_addMethod([self class], sel, (IMP)addedTheRuntimeTestMethod, "v@:");

        return YES;

    }

    return [super resolveInstanceMethod:sel];

}

@end

调用方式:

RuntimeObject *object = [[RuntimeObject alloc]init];

//    [object runtimeTest];

    [object performSelector:@selector(runtimeTest)];


运行结果:

2015-04-04 23:32:14.811 Test_4_4[2787:1225177] addedTheRuntimeTestMethod execute !


可见我们用runtime添加的方法执行了。

今天就到这里吧,更多精彩,最近会继续~




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值