我们接下来看看类对象的本质,其实就是下面这个结构体:
struct objc_class : objc_object {
Class isa;//这个isa指针本来是在objc_object里面的,现在把它拿上来这里
Class superclass;//指向父类的指针
cache_t cache; // 方法缓存
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
}
最后一个bits存储着非常多的东西,跟之前说的位域一样,想要取出某些东西必须bits&XX_MASK掩码。比如我们要取出这个类对象里面存储的data数据class_rw_t,则必须bits&FAST_DATA_MASK得到class_rw_t。
struct class_rw_t {//re=read write可读写的
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;//ro=read only是只读的,无法修改的
method_array_t methods;//方法列表,如果是元类对象,那么放的就是类方法
property_array_t properties;//属性列表
protocol_array_t protocols;//协议列表
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
}
这个class_rw_t是可读写的,我们runtime运行时可以动态读写里面的信息,比如增加协议,方法,属性等。
class_ro_t的结构如下:
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;//instance对象占用的内存空间
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;//类名
method_list_t * baseMethodList;//方法列表
protocol_list_t * baseProtocols;//协议列表
const ivar_list_t * ivars;//成员变量列表
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};

class_rw_t里面的methods、properties、protocols是二维数组,是可读可写的,包含了类的初始内容、分类的内容。
比如methods里面存放的是method_list_t数组,method_list_t数组里面装的才是method_t
class_ro_t里面存放的baseMethodList、baseProtocols、ivars是类里面本身初始化的方法、协议和属性不包括分类的,这些是一维数组,是不可更改的。
当我们的程序运行起来的时候系统会将class_ro_t里面的方法生成一个method_list_t数组放到class_rw_t的methods里面,并且分类里面的方法数组也会生成一个method_list_t合并到class_rw_t的methods里面,我们运行时动态修改方法就是只能修改class_rw_t里面的方法。
iOS方法的内部实现实际上是这样:
struct method_t {
SEL name;//函数名
const char *types;//编码(返回值类型、参数类型)
IMP imp;//指向函数的指针(函数地址)
}
SEL name函数名其实就是@selector(test),说白了这个就是函数名字符串
const char *types编码包含了函数的返回值类型和参数类型,比如以下test方法:
- (void) test{}
它的types是v16@0:8,v表示返回值类型是void,@表示id类型,:代表SEL类型,每个OC方法底层默认都会自带两个参数-(void)test:(id)self _cmd:(SEL)_cmd{}
cache_t cache; 是用一个散列表将曾经调用过的方法缓存起来,下次调用的时候直接从缓存里面拿,从基类里面找到的方法也会缓存到它的类对象里面,这样下次调用就不用一层一层去找了。
cache_t结构如下:
struct cache_t {
struct bucket_t *_buckets;//散列表
mask_t _mask;//散列表的长度 -1
mask_t _occupied;// 以及缓存的方法数量
}
struct bucket_t {
cache_key_t _key;//SEL作为Key即@selector(test)
IMP _imp;//函数的内存地址
}
当我们在散列表找方法时,我们拿@selector(test) & _mask得到对应的索引,然后拿函数地址与对应索引的函数地址比较,如果不对,那么_mask减1,如果_mask为0,则_mask就赋值为散列表的长度继续找。如果散列表扩容了,那么编译器会清空缓存,即清空散列表,然后再重新存取。
OC调用一个方法实质就是通过objc_msgSend方法向这个对象发送一条消息。主要有三大流程:消息查找发送、动态方法解析、消息转发
消息发送



我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/
似乎无法为此找到有效的答案。我正在阅读Rails教程的第10章第10.1.2节,但似乎无法使邮件程序预览正常工作。我发现处理错误的所有答案都与教程的不同部分相关,我假设我犯的错误正盯着我的脸。我已经完成并将教程中的代码复制/粘贴到相关文件中,但到目前为止,我还看不出我输入的内容与教程中的内容有什么区别。到目前为止,建议是在函数定义中添加或删除参数user,但这并没有解决问题。触发错误的url是http://localhost:3000/rails/mailers/user_mailer/account_activation.http://localhost:3000/rails/mai
给定以下方法:defsome_method:valueend以下语句按我的预期工作:some_method||:other#=>:valuex=some_method||:other#=>:value但是下面语句的行为让我感到困惑:some_method=some_method||:other#=>:other它按预期创建了一个名为some_method的局部变量,随后对some_method的调用返回该局部变量的值。但为什么它分配:other而不是:value呢?我知道这可能不是一件明智的事情,并且可以看出它可能有多么模棱两可,但我认为应该在考虑作业之前评估作业的右侧...我已经在R
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm
我正在使用带有Rails的Devise,我想添加一个方法“getAllComments”,所以我这样写:classUser在我的Controller中:defdashboard@user=current_user@comments=@user.getAllComments();end当我访问我的url时,我得到了undefinedmethod`getAllComments'for#我做错了什么?谢谢 最佳答案 因为getAllComments是一个类方法,而您正试图将其作为实例方法访问。您要么需要访问它:User.getAllCom
我正在尝试获得良好的Ruby编码风格。为防止意外调用具有相同名称的局部变量,我总是在适当的地方使用self.。但是现在我偶然发现了这个:classMyClass上面的代码导致错误privatemethodsanitize_namecalled但是当删除self.并仅使用sanitize_name时,它会起作用。这是为什么? 最佳答案 发生这种情况是因为无法使用显式接收器调用私有(private)方法,并且说self.sanitize_name是显式指定应该接收sanitize_name的对象(self),而不是依赖于隐式接收器(也是
我遇到了一些Ruby代码,我试图理解为什么变量在initialize方法声明中的名称末尾有冒号。冒号有什么原因吗?attr_reader:var1,:var2definitialize(var1:,var2:)@var1=var1@var2=var2end 最佳答案 那些是关键字参数。您可以按名称而非位置使用它们。例如ThatClass.new(var1:42,var2:"foo")或ThatClass.new(var2:"foo",var1:42)Anarticleaboutkeywordargumentsbythoughtbot
使用Ruby1.8.6/Rails2.3.2我注意到在我的任何ActiveRecord模型类上调用的任何方法都返回nil而不是NoMethodError。除了烦人之外,这还破坏了动态查找器(find_by_name、find_by_id等),因为即使存在记录,它们也总是返回nil。不从ActiveRecord::Base派生的标准类不受影响。有没有办法追踪在ActiveRecord::Base之前拦截method_missing的是什么?更新:切换到1.8.7后,我发现(感谢@MichaelKohl)will_paginate插件首先处理method_missing。但是will_pa
Ruby初学者努力简单地将这个@@people散列的值打印到控制台classPerson#haveafirst_nameandlast_nameattributewithpublicaccessorsattr_accessor:first_nameattr_accessor:last_name#haveaclassattributecalled`people`thatholdsanarrayofobjects@@people=[]#havean`initialize`methodtoinitializeeachinstancedefinitialize(first_name,last_