在OC当中,属性是对字段的一种特殊封装手段。

在编译期,编译器会将对字段的访问替换为内存偏移量,实质是一种硬编码。

如果增加一个字段,那么对象的内存排布就会改变,需要重新编译才行。

OC的做法是,把实例变量当做一种存储偏移量所用的特殊变量交给类对象来管理,偏移量会在运行期动态查找,这样无论何时访问实例变量,总能找到正确的地址。

可以在对象的内部(.m当中)直接使用下划线变量而不用getter或setter,会绕过方法派发过程,绕过内存管理和线程安全管理语义,会提升性能,同样不会触发KVO,会避免调用子类复写的setter方法。

在OC当中,所有对方法都会编译成C函数,当对象收到消息的时候,所有对函数的调用都由运行期动态绑定,甚至可以改写。

发送消息的代码是objc_msgSend(id, SEL, …)

收到消息的对象会去其方法表里找SEL,如果找不到就沿着继承体系向上找,如果最终还是找不到,则执行消息转发。

每个类当中都有一个快速映射表(缓存区),执行过的方法会缓存到这里,减少搜索时间。

当运行时找到对应的方法实现时,就会跳转过去,执行对应的C函数:

函数名大概是这个形式的:<返回值> Class_selector(id, SEL, …)

每个类里都有这样一张表格(方发表),key就是SEL,value就是IMP指针。objc_msgSend就是通过这个表找方法的。

上面是消息派发过程,OC还有消息转发过程。

当一个对象接收到无法执行的消息时,会调用

+(BOOL)resolveInstanceMethod:(SEL)selector

可以在这个方法里通过运行时动态创建一个方法来接受这个消息。

如果没有实现,则去找resolveClassMethod:方法。

CoreData当中@dynamic属性的get/set方法就是用这种手段生成的。

生成的过程当中,需要为这个selector指定一个IMP指针,这个指针指向一个C函数,比如CoreData操纵数据库的sqlite函数。

建议在这一步,就完成消息转发,因为这样会将选择子加入缓存。

如果这个阶段并没有为类添加方法,则运行时会询问能不能把这条消息交给其他备选接受者来处理。对应的方法:

-(id)forwardingTargetForSelector:(SEL)selector

如果没有方法来处理,则需要返回nil。

显然我们可以通过这个机制给一个对象内部组合另一个对象来处理某些方法,这样就模拟了多继承。

如果到了这一步依旧没有处理消息,则会触发

-(void)forwardInvocation:(NSInvocation *)invocation

NSInvocation当中封装了SEL、target和参数,这是最后一次改变消息路线的机会了。

如果还没有处理消息,则会抛异常。

在运行时检查对象的类型的过程叫做内省。

OC对象其实是id类型,

objc_object 是一个结构体,一个这种结构体类型的指针就是一个id。

这个结构体内部,含有一个Class类型的变量isa。

类似的,还有一个结构体类型叫objc_class,指向它的指针就是Class。

这个结构体里面存放一个类的元数据:

首先,它内部存储了一个Class isa变量,它指向类的元类。

这个类里面有:

元类指针,父类指针,名字,版本,info,实例size,指向变量表的指针,指向方法表的指针的指针,指向缓存表的指针,指向协议表的指针。

两个元类之间也有继承关系。根类的元类的元类就是自身。

isMemberOfClass:和isKindOfClass就是通过objc_class当中的指针来确定结果的。

OC运行时和方法机制笔记的更多相关文章

  1. Objective-C运行时编程 - 方法混写 Method Swizzling

    摘要: 本文描述方法混写对实例.类.父类.不存在的方法等情况处理,属于Objective-C(oc)运行时(runtime)编程范围. 编程环境:Xcode 6.1.1, Yosemite,iOS 8 ...

  2. 趣谈iOS运行时的方法调用原理

    一个成熟的计算机语言必然有丰富的体系,复杂的容错机制,处理逻辑以及判断逻辑.但这些复杂的逻辑都是围绕一个主线丰富和展开的,所以在学习计算机语言的时候,先掌握核心,然后了解其原理,明白程序语言设计的实质 ...

  3. Java的运行时数据存储机制

    原文地址:http://yanwushu.sinaapp.com/java_data_storage/ Java程序在运行时需要为一系列的值或者对象分配内存,这些值都存在什么地方?用什么样的数据结构存 ...

  4. java 利用java运行时的方法得到当前屏幕截图的方法(转)

    将截屏图片保存到本地路径: package com.test; import java.awt.AWTException; import java.awt.Dimension; import java ...

  5. C# 运行时替换方法(需要unsafe编译)

    /* https://stackoverflow.com/questions/7299097/dynamically-replace-the-contents-of-a-c-sharp-method ...

  6. 通过运行时动态给OC分类添加属性

    #import <UIKit/UIKit.h> /** iOS 开发中,分类默认不允许保存属性 如果在分类中,定义一个属性,需要自己实现 getter & setter 方法,而且 ...

  7. 由objC运行时所想到的。。。

    objC语言不仅仅有着面向对象的特点(封装,继承和多态),也拥有类似脚本语言的灵活(运行时),这让objC有着很多奇特的功能-可在运行时添加给类或对象添加方法,甚至可以添加类方法,甚至可以动态创建类. ...

  8. Objective-C Runtime 运行时之一:类与对象

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

  9. Objective-O Runtime 运行时初体验

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

随机推荐

  1. SQL别名解析(转载)

    通过使用 SQL,可以为列名称和表名称指定别名(Alias). 其实,select列的时候取别名有三种方法,这三种方法并不是所有数据库都适用. 方法一.直接在字段名称后面加上别名,中间以空格隔开. 方 ...

  2. 一道C语言面试题:得到整数的M进制表示字符串

    题目:输入整数n和M,输出n在M进制下的表示字符串.如n=3000,M=16,输出16进制下3000的表示字符串,为“BB8” 来源:某500强企业面试题目 思路:对n取模M,将得到的数字压入栈中,再 ...

  3. QT父子与QT对象delete

    原地址:http://www.qteverywhere.com/archives/437 很多C/C++初学者常犯的一个错误就是,使用malloc.new分配了一块内存却忘记释放,导致内存泄漏.Qt的 ...

  4. Chapter 1. Hello, Perl/Tk

    Chapter 1. Hello, Perl/Tk 内容: Perl/Tk Concepts Some Perl/Tk History Getting Started with Perl/Tk Hel ...

  5. Unix/Linux环境C编程入门教程(30) 字符串操作那些事儿

    函数介绍 rindex(查找字符串中最后一个出现的指定字符) 相关函数 index,memchr,strchr,strrchr 表头文件 #include<string.h> 定义函数 c ...

  6. UDP包的大小与MTU

    在进行UDP编程的时候,我们最容易想到的问题就是,一次发送多少bytes好?当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的,我这里仅对像ICQ一类的发送聊天消息的情况作分 ...

  7. 利用COM组件IPicture读取jpg、gif、bmp图片文件数据和显示图片

    1.读取图片数据 函数原型:bool LoadImage(const char *pName, unsigned char *pBitData); 函数功能,读取pName指向的图片文件的位图数据 b ...

  8. uva10820 send a table (nlogn求1-n欧拉函数值模版

    //重点就是求1-n的欧拉函数啦,重点是nlogn求法的版 //大概过程类似于筛选法求素数 #include<cstdio> #include<iostream> #inclu ...

  9. Unity doesn't load, no Launcher, no Dash appears

    1. 重新安装 ubuntu-desktop不起作用. Enter the following commands:- Ctrl+Alt+F1 login there by user name and ...

  10. poj 1887 Testing the CATCHER_最长上升子序列

    题意:题目太长没看,直接看输入输出猜出是最长下降子序列 用了以前的代码直接a了,做法类似贪心,把最小的顺序数存在数组里面,每次二分更新数组得出最长上升子序列 #include<iostream& ...