iOS-Runtime、对象模型、消息转发

Objective-C只是在C语言层面上加了些关键字和语法。真正让Objective-C如此强大的是它的运行时。它很小但却很强大。它的核心是消息分发。html

Messageios

  执行一个方法,有些语言、编译器会执行一些额外的优化和错误检查,由于调用的关系很直接也很明显。可是对于消息分发来讲,就不必定了。在发消息前没必要知道某个对象是否能处理消息,你把消息发给它,它可能会处理,也可能会交给其余的objec 处理。一个消息不用对应一个方法、一个对象也可能实现一个方法来处理多条消息。objective-c

在objcetive中,消息是经过objc_msgSend()这个runtime实现的。编译器把消息的分发转变成objc_msgSend执行。缓存

id returnValue = [someobject messagename:parameter];

其中someObject是接收者(receiver),messagename叫作Selector,Selector和参数合起来叫作消息.函数

objc_msgSend(id self, sel cmd,...)

第一个参数表明接收者,第二个参数是Selector,后面的参数就是消息中得参数,位置顺序不变。因此根据上面的原型,咱们能够把函数改写成这样:优化

id returnValue = objc_msgsend(someobject,@selector(messagename:),parameter);

  objc_msgsend函数会根据接受者和selector的类型调用适当的方法。会在接收者所属的类里面搜寻“方法列表”(list of method).若是能找到与selector名称相符合的方法,就跳转至实现代码。若是找不到的话,就会向上查找,等找到合适的方法后跳转。若是仍是找不到得话就会执行“消息转发”的操做。spa

  按照这个思路,调用一个方法须要不少步骤。可是objc_msgsend会将结果缓存到快速映射表(fast map)里面,每一个类都有一个这样的缓存,如果稍后还向该类发送相同的消息的话,执行起来就很快了。3d

对象某型

打开NSObject.h能够看见下面object_class的组成指针

打开runtime.h能够看见下面object_class的组成调试

 

isa指针:每一个对象都是类的实例,isa指针指向这个实例所属的类,每一个类也是一个对象,类也有isa指针。

super_class:父类

name:类的名字

info:类的一些信息

instance_size:实例的大小

objc_ivar_list:实例的参数列表

objc_method_list:实例的方法列表

objc_cache:方法的缓存

objc_protocol_list:协议方法列表

 

借用网上的一张图:图片来自这里

 

根据这张图片,能够发现有如下信息:

(1)类也是一个对象,这个对象是另一个类的实例,这个类是meta(元类)

  (2) 每一个meta类也是一个对象,分别指向根meta类。

(3)根元类的isa指针指向本身,造成了一个闭环。

(4)在继承关系中,因为类方法的定义是保存在元类(metaclass)中,而方法调用的规则是,若是该类没有一个方法的实现,则向它的父类继续查找。因此,为了保证父类的类方法能够在子类中能够被调用,因此子类的元类会继承父类的元类,换而言之,类对象和元类对象有着一样的继承关系。

Method Swizzling

Method Swizzling 能够交换两个方法的实现。为何会有这样的功能呢?首先看看扩展类的两种途径,第一种是子类化,重写父类的方法,而后调用父类的实现。可是使用子类的过程当中,若是返回的时父类的类型的话怎么办?能够使用Category,添加一个扩展方法,这个方法若是没有和系统调用的方法重名的话通常状况下是没有问题的,可是若是重写了系统的方法的话,那么就永远不能调用这个方法了。因此Method Swizzling这个方法能解决这些问题,技能扩展类,又还能调用原来类的实现,一般状况下先创建一个与系统对应的扩展类,而后经过method_exchangeImplementations方法交换它们的实现。

首先定义一个NSString的扩展类

@interface NSString (Addition)
- (NSString *)test_myLowerString;
@end
@implementation NSString (Addition)

- (NSString *)test_myLowerString
{
    NSString *lowercase = [self test_myLowerString];
    NSLog(@"%@ =>%@",self,lowercase);
    return lowercase;
}

@end

而后交换它们的实现方法

    NSString *testString = @"TEST";
    NSLog(@"%@,",[testString lowercaseString]);
    
    Method originMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
    Method swapMethod = class_getInstanceMethod([NSString class], @selector(test_myLowerString));
    method_exchangeImplementations(originMethod, swapMethod);
    NSLog(@"%@",[testString lowercaseString]);

打印的结果是:

因此咱们改写了系统的lowercaseString方法,每当咱们调用扩展的test_myLowerString方法时候,实际上是调用系统的lowercaseString方法,这种作法通常状况用在调试系统,不过最好不建议改写系统的一些方法,可能会带来不可调试的后果,因此使用前需慎重。

动态方法处理和消息转发

上面谈了方法的交换,是对消息处理的一种,下面再谈另一种方法的处理

 

参考连接

 http://blog.devtang.com/blog/2013/10/15/objective-c-object-model/

http://limboy.me/ios/2013/08/03/dynamic-tips-and-tricks-with-objective-c.html

相关文章
相关标签/搜索