OC运行时和方法机制笔记

在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当中的指针来确定结果的。

时间: 2024-08-29 23:22:26

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

OC运行时编程指南

一.介绍 OC这个语言尽可能的将一些决定从编译和链接时推迟到运行时.它会尽可能的动态的处理事情.这意味这个语言不仅需要一个编译器,还需要一个运行时系统去执行编译过的代码.这个运行时系统扮演着对于OC这个语言操作系统的的角色,使得这个语言得以运行. 这个教程将探究NSObject这个类以及OC这个语言和运行时系统是如何进行交互的.特别是如何在运行时动态的根据类的范式加载类,并且传递给其他对象.同时这个教程还将告诉你如何在你的程序运行过程中找到你的对象的运行信息. OC运行时编程指南描述了OC运行时

运行时在方法内部获取该方法的名称及参数相关信息

package com.dongjak.scripts.java.反射; import java.lang.reflect.Method; import net.sf.json.JSONObject; import com.dongjak.annotations.LogTarget; /** * * @author dongjak * * */ public class 运行时在方法内部获取该方法的名称及参数相关信息 { public static void main(String[] args

运行时类信息机制

// MFCDynimic.cpp : Defines the entry point for the console application.///*运行时类信息机制:在程序运行过程中,可以判断类对象的相关类的信息以及继承派生类.*/ #include "stdafx.h"#include "MFCDynimic.h" class CAnimal:public CObject{DECLARE_DYNAMIC(CAnimal);}; IMPLEMENT_DYNAMI

运行时之方法交换

在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写.和借助类别重名方法暴力抢先之外,还有就是方法交换 方法交换的原理:在OC中调用一个方法其实是向一个对象发送消息,查找消息的唯一依据是selector的名字.利用OC的动态特性,可以实现在运行时偷换selector方法的实现,达到和方法挂钩的目的. 每一个类都有一个方法列表,存放在selector的名字和方法实现的映射关系,imp有点像函数指针,指向具体的方法实现. 可以利用method_exchanggeimplement

Java的运行时数据存储机制

原文地址:http://yanwushu.sinaapp.com/java_data_storage/ Java程序在运行时需要为一系列的值或者对象分配内存,这些值都存在什么地方?用什么样的数据结构存储?这些数据结构有什么特点?本文试图说明此命题的皮毛之皮毛. 概念 对于Java,有六个不同的.用于数据存储的概念,他们是: 1.     寄存器( register),是最快的存储区,位于处理器内部.因为寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配.程序员无法使用Java代码使用寄存器

关于对OC运行时机制的理解

首先,第一个问题, 1>runtime实现的机制是什么,怎么用,一般用于干嘛? 这个问题我就不跟大家绕弯子了,直接告诉大家, runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API. 在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者 比如说,下面一个创建对象的方法中, 举例: OC : [[MJPerson alloc] init] runtime : objc_msgSe

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

第一种方法的基本原理是将函数指针替换成想要的方法(https://stackoverflow.com/questions/7299097/dynamically-replace-the-contents-of-a-c-sharp-method):还有一种方式是用 methodInfo.GetMethodBody().GetILAsByteArray() 获得IL字节码,然后(利用C++?)编写注入代码对其字节码重新写入(https://www.codeproject.com/Articles/4

运行时(方法交换)

Method method1 = class_getInstanceMethod([XMGPerson class], @selector(run)); Method method2 = class_getInstanceMethod([XMGPerson class], @selector(study)); method_exchangeImplementations(method1, method2);

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

将截屏图片保存到本地路径: package com.test; import java.awt.AWTException; import java.awt.Dimension; import java.awt.HeadlessException; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io