Runtime 01

作者: __Guan__ | 来源:发表于2016-06-30 23:59 被阅读103次

Runtime学习笔记,希望大牛们指正。

Messaging

The objc_msgSend Function

在OC中,到运行时消息才会绑定在方法实现上,编译器会转换消息的表达式,[receiver message]会被转化成:
objc_msgSend(receiver, selector)
任何在消息中传递的参数,都会传递给objc_msgSend:
objc_msgSend(receiver, selector, arg1, arg2, ...)

例如:
新建一个LinObject的类,在.m文件中,这样写:

#import "LinObject.h"

@implementation LinObject

- (instancetype) init {
    if (self = [super init]) {
        [self doSomething];
    }
    return self;
}

- (void)doSomething {
    NSLog(@"I'm learning");
}

@end

之后使用终端,到文件目录下,执行命令:
$ clang -rewrite-objc MyClass.m
然后回到文件目录下,可以找到一个cpp文件,其中可以看到,类中的实现,被转换成了:

static instancetype _I_LinObject_init(LinObject * self, SEL _cmd) {
    if (self = ((LinObject *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("LinObject"))}, sel_registerName("init"))) {
        ((void (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("doSomething"));
    }
    return self;
}

苹果官方的备注:

Note: The compiler generates calls to the messaging function. You should never call it directly in the code you write.

意思就是,你永远不要直接使用这个方法。
每当创建一个新的对象时,会分配一块内存,并且它的引用对象也会被初始化。在对象的变量中,首先是指向它的结构体类的指针。这个指针叫做isa,指向该对象的类、父类、所有在这个类的继承关系中的类。

Note: While not strictly a part of the language, the isa pointer is required for an object to work with the Objective-C runtime system. An object needs to be "equivalent" to a struct objc_object (defined in objc/objc.h) in whatever fields the structure defines. However, you rarely, if ever, need to create your own root object, and objects that inherit from NSObject or NSProxy automatically have the isa variable.

严格来说,isa不是语言的一部分,但是这个指针在OC的运行时系统中不可或缺。一个对象必须“等价于”一个objc_object结构体(定义在objc/objc.h中),无论结构体在哪里被定义。然而,只有在很少的情况下需要创建自己的基类对象,继承自NSObject或者NSProxy的对象都会自动拥有isa变量。

isa示意图.png

Using Hidden Arguments

当 objc_msgSend找到方法的实现之后,在调用方法的时候,总会传递两个隐藏的参数:

  • 接收的对象(id)
  • 方法的选择器(SEL)

id:

typedef struct objc_object *id;

id是一个结构体指针类型,它可以指向 Objective-C 中的任何对象。objc_object 结构体定义如下:

struct objc_object { Class isa OBJC_ISA_AVAILABILITY;};

SEL:

typedef struct objc_selector *SEL;

是表示一个方法的selector的指针,映射方法的名字。可以用runtime库的 sel_registerName 函数来获得。

Getting a Method Address

绕过动态绑定的唯一方法只有获取方法地址然后直接调用。在某些场合,这可能是最适合当一个方法将会被连续执行多次,并且你还想避免每次执行方法时的消耗。

NSObject类中定义的一个方法,methodForSelector:,你可以请求一个指向这个方法的实现的指针,然后使用这个指针来调用这个实现。这个methodForSelector:指针的返回值必须是一个适当的函数类型。无论是返回值还是参数类型都应该被包括在内。

这个例子展示了setFilled:的实现是如何被调用的:

void (*setter)(id, SEL, BOOL);
int i;
setter = (void (*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)];
for ( i = 0 ; i < 1000 ; i++ ) {
  setter(targetList[i], @selector(setFilled:), YES);
}

前两个参数分别是消息接收者(self)和方法选择器(_cmd)。这两个参数在语法上都被隐藏了,但是当方法被调用时都必须明确。
使用methodForSelector:来避开动态绑定节省了发送消息所需的必要时间。然而,只有当一个指定的消息像在for循环中那样被重复发送多次,才是有意义的。
methodForSelector:是Cocoa runtime 系统中提供的方法,而不仅仅是Objective-C语言自身的特性。

相关文章

  • runtime02-常用API

    runtime常用API runtime API01-类相关 runtime API01-类相关-事例01 run...

  • 2020-02-23 Runtime

    目录: 01-Runtime 初探 02-Runtime 对象与方法的本质 03-Runtime 动态方法解析 0...

  • 01·iOS 面试题·项目中用过 Runtime 吗?

    01·iOS 面试题·项目中用过 Runtime 吗? 01·iOS 面试题·项目中用过 Runtime 吗?

  • 01 - Runtime

    1.0 Runtime介绍 1.1 Runtime简介 1.2 Runtime总结 1.3 Objective-C...

  • Runtime 01

    Runtime学习笔记,希望大牛们指正。 Messaging The objc_msgSend Function ...

  • Runtime 01 - isa

    Runtime 01 - isa Runtime 又叫运行时,是一套 C 语言的 API,Objective-C ...

  • Runtime学习01

    Runtime.h runtime开篇定义了四个类型 上述四行代码分别 定义Method 为指向objc_meth...

  • runtime_01

    首先感谢祖国,可以无忧无虑的码代码 ~ If I have seen further, it is by stan...

  • Objective-C的runtime机制02-消息机制

    上一篇《Objective-C的runtime机制01-重要数据结构和内部关系图》说了runtime的内部数据结构...

  • 三十一、Runtime之(十四)Runtime相关API

    Runtime相关API01—类 1.动态创建一个类,并为该类添加成员变量和方法。 Runtime相关API02 ...

网友评论

    本文标题:Runtime 01

    本文链接:https://www.haomeiwen.com/subject/tnyxjttx.html