Runtime 是什么?

objective-C会把函数调用的转换为消息发送,objc_MsgSend(receiver, msg), 注意,recevier指的是消息的接受者。那么self, super的区别是什么?其实 super 是一个 Magic Keyword, 它本质是一个编译器标示符,和 self 是指向的同一个消息接受者!他们两个的不同点在于:super 会告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。不管调用[self class]还是[super class],接受消息的对象都是当前 self指向的实例。在代码中使用self可以获取recevier,使用_cmd获取method。

1.SEL 的含义:

在前面我们看到方法选标 SEL 的定义为:

它是一个指向 objc_selector 指针,表示方法的名字/签名。

typedef struct objc_selector   *SEL;   

2. IMP 的含义:

在前面我们也看到 IMP 的定义为:

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

根据前面id 的定义,我们知道 id是一个指向 objc_object 结构体的指针,该结构体只有一个成员isa,所以任何继承自 NSObject 的类对象都可以用id 来指代,因为 NSObject 的第一个成员实例就是isa。

至此,我们就很清楚地知道 IMP  的含义:IMP 是一个函数指针,这个被指向的函数包含一个接收消息的对象id(self  指针), 调用方法的选标 SEL (方法名),以及不定个数的方法参数,并返回一个id。也就是说 IMP 是消息最终调用的执行代码,是方法真正的实现代码 。我们可以像在C语言里面一样使用这个函数指针

3. Method是,包含了方法名称,与实现的结构。

typedef struct objc_method *Method;

typedef struct objc_ method {

    SEL method_name;

    char *method_types;

    IMP method_imp;

};

消息的转发

给一个对象调用它不存在的方法,会发生什么?

It works like this: When an object can’t respond to a message because it doesn’t have a method matching the selector in the message, the runtime system informs the object by sending it a forwardInvocation: message. Every object inherits a forwardInvocation: method from the NSObject class. However, NSObject’s version of the method simply invokes doesNotRecognizeSelector:. By overriding NSObject’s version and implementing your own, you can take advantage of the opportunity that the forwardInvocation: message provides to forward messages to other objects

会发生,forwardingInvocation:message, NSObject实现是doesNotRecongizeSelectoer:,所以我们可以重写这个实现。通过消息转发,调用其他类的实现,起到了多重继承的效果

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([someOtherObject respondsToSelector:
[anInvocation selector]])
[anInvocation invokeWithTarget:someOtherObject];
else
[super forwardInvocation:anInvocation];
}

替代的对象,如果一个类很大,很复杂,你想懒加载,可以先使用一个替代类进行占位,等到你需要的时候再消息转发。

If you want your objects to act as if they truly inherited the behavior of the objects they forward messages to, you’ll need to re-implement the respondsToSelector:and isKindOfClass: methods to include your forwarding algorithm:

如果再消息转发的情况下,支持某些方法,如何感知,需要重写自己版本的几个函数

- (BOOL)respondsToSelector:(SEL)aSelector
{
if ( [super respondsToSelector:aSelector] )
return YES;
else {
/* Here, test whether the aSelector message can *
* be forwarded to another object and whether that *
* object can respond to it. Return YES if it can. */
}
return NO;
}

如果一直找到根类都没有找到对应的方法,object_msgForward就作为替代IMP,并执行

objc_msgForward消息转发做的几件事:

调用resolveInstanceMethod:方法 (或resolveClassMethod:)。允许用户在此时为该 Class 动态添加实现。如果有实现了,则调用并返回YES,那么重新开始objc_msgSend流程。这一次对象会响应这个选择器,一般是因为它已经调用过class_addMethod。如果仍没实现,继续下面的动作。

调用forwardingTargetForSelector:方法,尝试找到一个能响应该消息的对象。如果获取到,则直接把消息转发给它,返回非 nil 对象。否则返回 nil ,继续下面的动作。注意,这里不要返回 self ,否则会形成死循环。

This method gives an object a chance to redirect an unknown message sent to it before the much more expensive forwardInvocation: machinery takes over. This is useful when you simply want to redirect messages to another object and can be an order of magnitude faster than regular forwarding. It is not useful where the goal of the forwarding is to capture the NSInvocation, or manipulate the arguments or return value during the forwarding.

调用methodSignatureForSelector:方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。如果能获取,则返回非nil:创建一个 NSlnvocation 并传给forwardInvocation:。

This method is used in the implementation of protocols. This method is also used in situations where an NSInvocation object must be created, such as during message forwarding. If your object maintains a delegate or is capable of handling messages that it does not directly implement, you should override this method to return an appropriate method signature.

调用forwardInvocation:方法,将第3步获取到的方法签名包装成 Invocation 传入,如何处理就在这里面了,并返回非ni。

调用doesNotRecognizeSelector:,默认的实现是抛出异常。如果第3步没能获得一个方法签名,执行该步骤。

Important

To respond to methods that your object does not itself recognize, you must override methodSignatureForSelector: in addition to forwardInvocation:. The mechanism for forwarding messages uses information obtained from methodSignatureForSelector: to create the NSInvocation object to be forwarded. Your overriding method must provide an appropriate method signature for the given selector, either by pre formulating one or by asking another object for one.

To assist the runtime system, the compiler encodes the return and argument types for each method in a character string and associates the string with the method selector. The coding scheme it uses is also useful in other contexts and so is made publicly available with the @encode() compiler directive

Objects are treated like structures. For example, passing the NSObject class name to @encode() yields this encoding:, NSObject就只有一个isa指针

{NSObject=#}

之前用MJExtension在多线程下一直崩溃,后来MJExtension修复了,就是加了一个同步, https://github.com/CoderMJLee/MJExtension/issues/518

+ (instancetype)cachedTypeWithCode:(NSString *)code

{

MJExtensionAssertParamNotNil2(code, nil);

@synchronized (self) {

MJPropertyType *type = types_[code];

if (type == nil) {

type = [[self alloc] init];

type.code = code;

types_[code] = type;

}

return type;

}

}

MJExtension代码解释的更多相关文章

  1. Deep Learning入门视频(下)之关于《感受神经网络》两节中的代码解释

    代码1如下: #深度学习入门课程之感受神经网络(上)代码解释: import numpy as np import matplotlib.pyplot as plt #matplotlib是一个库,p ...

  2. [ARM] Cortex-M Startup.s启动文件相关代码解释

    1. 定义一个段名为CSTACK, 这里: NOROOT表示如何定义的段没有被关联,那么同意会被优化掉,如果不想被优化掉就使用ROOT. 后面的括号里数字表示如下: (1):这个段是2的1次方即2字节 ...

  3. word2vec代码解释

    以前看的国外的一篇文章,用代码解释word2vec训练过程,觉得写的不错,转过来了 原文链接 http://nbviewer.jupyter.org/github/dolaameng/tutorial ...

  4. javascript代码解释执行过程

    javascript是由浏览器解释执行的脚本语言,不同于java c,需要先编译后运行,javascript 由浏览器js解释器进行解释执行,总的过程分为两大块,预编译期和执行期 下面的几个demo解 ...

  5. 临时2级页表的初始化过程 head_32.S 相关代码解释

    page_pde_offset = (__PAGE_OFFSET >> 20); /* __PAGE_OFFSET是0xc0000000,page_pde_offset = 3072 = ...

  6. 零基础学python之入门和列表数据(附详细的代码解释和执行结果截图)

    Python学习笔记 1 快速入门 下载安装好Python之后,在开始找到 双击打开一个窗口,这是一个shell界面编辑窗口,点击左上角的file——new file新建一个窗口,这里可以输入完整的代 ...

  7. java 的一个hellow word 代码解释

    /* This is a simple Java program. Call this file "Example.java". */(上面是注释的方法) class Exampl ...

  8. TensorFlow的序列模型代码解释(RNN、LSTM)---笔记(16)

    1.学习单步的RNN:RNNCell.BasicRNNCell.BasicLSTMCell.LSTMCell.GRUCell (1)RNNCell 如果要学习TensorFlow中的RNN,第一站应该 ...

  9. 参数传递方法(用Delphi的汇编代码解释)

    参数传递方法 李纬的InsideVCL<第一章>中提到Windows定义的回调函数 typedef LRESULT (CALLBACK*WNDPROC)(HWND,UNIT,WPARAM, ...

随机推荐

  1. mtd工具

    http://daemons.net/linux/storage/mtd.html MTD The Memory Technology Devices (MTD) subsystem provides ...

  2. python中的风险

    from math import e print(e) e = "中华人民共和国1" print(e) 输出: 2.718281828459045 中华人民共和国1 用from方式 ...

  3. [No0000D5]便利所有子目录更改后缀名bat

    pause for /r %%i in (.) do ( cd %%i ren *.txt *.dll ) pause

  4. 【魔改】莫队算法+组合数公式 杭电多校赛4 Problem B. Harvest of Apples

    http://acm.hdu.edu.cn/showproblem.php?pid=6333 莫队算法是一个离线区间分块瞎搞算法,只要满足:1.离线  2.可以O(1)从区间(L,R)更新到(L±1, ...

  5. python-爬虫:取qq号中各分组成员信息存入数据库,并将qq头像下载保存到文件夹,图片命名为qq号(实例3)

    import requestsimport pymongoimport requestsimport os class QqGroup:#三个接口url 获取 qq组号 获取每组成员信息 获取qq头像 ...

  6. HDMI 接口及CEC信号

    HDMI 接口及CEC信号 2016年12月02日 14:16:38 King-Five 阅读数:16389 HDMI接口 HDMI(High Definition Multimedia Interf ...

  7. dyld环境变量

    苹果APP启动,分为两个过程:系统dylib动态链接库 app的main函数启动过程. main函数过程直接对iOS开发者.这里备忘的dylib过程: 一.dyld加载到虚拟内存     1. loa ...

  8. pip离线安装python包

    1 首先在一台能上网的机器上得到python包 1) 新建一个空目录,如 /home/ubuntu/zcy/ss,用来存储下载下来的所需安装包 2)下载安装包:pip install --downlo ...

  9. 转:Java properties | FileNotFoundException: properties (系统找不到指定的文件。)

    原文地址:https://blog.csdn.net/cor_twi/article/details/44514871 web项目 (dynamic web project ) 读取propertie ...

  10. Oracle 分区表 收集统计信息 参数granularity

    GRANULARITY Determines the granularity of statistics to collect. This value is only relevant for par ...