利用clang命令,可以把oc代码编译成C++,我们可以看到类都是结构体
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Person.m
具体见这篇博客
需要注意的是:objc_selector方法编号,是以方法名为唯一标记的,不包含参数,objcMsgSender(id(方法接受者),selector,参数1,参数2,.....)
对象的本质是结构体
LGPerson *p = [[LGPerson alloc] init];
LGPerson *p = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("new"));
方法的本质 --- 发送消息
objc_msgSend ? 消息的组成 ((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));
void *)objc_msgSend)((id)p 消息接受者
sel_registerName("run") 方法编号 --- name
imp 函数实现的指针 -- sel -> imp ?
关于类的讲解先看这篇博客:www.jianshu.com/p/45fe90253…
[self class]和[super class]
有个继承自NSobject的类Person,它有个子类Student,在子类里打印[self class]和[super class],打印结果是怎样的?结果是
2019-08-12 14:43:29.341534+0800 01-Runtime 初探[34213:6419974] self class:LGStudent
2019-08-12 14:43:29.341549+0800 01-Runtime 初探[34213:6419974] super class:LGStudent
有点出乎意料,为了查清楚原因,我们把oc的代码转成C++的代码,cd到当前文件目录下,输入命令
xcrun -sdk iphonesimulator clang -rewrite-objc LGStudent.m
找到调用的地方
static void _I_LGStudent_log(LGStudent * self, SEL _cmd) {
((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("LGStudent"))}, sel_registerName("class"));
}
可以看到[self class],调用的是objc_msgSend,传入的第一个参数是self,其实就是消息的接受者,第二个参数是方法编号。因为调用的是实例方法,所以会从当前类的方法列表中查找selector,如果没有找到就查找superclass的方法列表。 而[super class]转换以后发现调用的是 objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...),先看第一个参数objc_super,它是一个结构体。
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
/* super_class is the first class to search */
};
第一个参数也是self,就是当前的student类,第二个参数应该是父类Person。整个过程如下
1.构建objc_super的结构体,此时这个结构体的第一个成员变量receiver就是LGStudent,和self相同。而第二个成员变量superClass就是指类LGPerson,因为Son的超类就是这个LGperson。
2.调用objc_msgSendSuper的方法,将这个结构体和setName的sel传递过去。函数里面在做的事情类似这样:从 objc_super结构体指向的superClass的方法列表开始找setName的selector,找到后再以 objc_super->receiver去调用这个selector,可能也会使用objc_msgSend这个函数,不过此时的第一个参数 theReceiver就是objc_super->receiver,第二个参数是从objc_super->superClass中找到 的selector。
补充:最近面试被问到一个问题,objc_msgsender(receiver,selector)传递的参数在哪里?当时把我一下子问懵啦,平时看博客,还是要多动手实操,多思考,注重细节,因为我们做技术的,细节不了解,很难把整个功能做的特别完善。回来自己研究了一下:自定一个person类,实现类一个实例方法:[zmodop setAge:@"meshare"andName:@"funlux"];转换成C++代码是这样的。
((void (*)(id, SEL, NSString * _Nonnull, NSString * _Nonnull))(void *)objc_msgSend)((id)(zmodop.__forwarding->zmodop), sel_registerName("setAge:andName:"), (NSString *)&__NSConstantStringImpl__var_folders_jt_p_s4qkbn7tn3s430s0tdp0680000gn_T_main_ba0904_mi_1, (NSString *)&__NSConstantStringImpl__var_folders_jt_p_s4qkbn7tn3s430s0tdp0680000gn_T_main_ba0904_mi_2);
可以看到,参数在后边。
这篇也写的不错: www.cnblogs.com/allanliu/p/…