5--类的底层探索之属性

361 阅读2分钟

成员变量 vs Property

Clang

首先先介绍一下clang, clang是一个由Apple主导编写,基于LLVMC/C++/OC的轻量级编译器 主要是用于底层编译,将一些文件输出成c++文件,例如main.m 输出成main.cpp,其目的是为了更好的观察底层的一些结构及实现的逻辑,方便理解底层原理.

探索

image.png 成员变量和属性的区别 基本数据类型(int float NSString*) 称为成员变量。 imp : 方法的具体实现,函数的指针。 cmd : 方法编号。 SEL : 方法的名字。

首先我们探索下property 和 成员变量在底层的结构是什么样的

clang -rewrite-objc main.m -o main.cpp 通过clangmain.m输出为main.cpp

image.png image.png image.png 从上述源码中我们可以看到所有的property都有生成对应的set/get方法,但是 为什么hobbyset方法是通过内存偏移的方式去赋值,而yyyName是通过objc_setProperty实现的呢? 那我们就去查看LLVM的源码,研究下为什么setYyyName会调用objc_setProperty, 下图是LLVM的源码创建setProperty的函数 image.png 我们再反推回去找什么地方调用的GetPropertySetFunction

image.png image.png 由上图可知,发现是通过switch strategy.getKind()来确定是否需要setProperty image.png image.png 终于在一番查找之后发现当是copyproperty的时候,strategy的赋值为GetSetProperty. 由此解释了为什么copyset方法是需要调用setProperty的原因.

探索

什么时候会生成objc_getProperty

image.png

image.png image.png

将工程改为mrc,我们会发现得到以下规律

atomic: 取值使用objc_getProperty (保证原子操作)
assign: 存储使用内存偏移 (不需要做retain,release)
retain: 存储使用objc_setProperty (保证release 老值,retain 新值)

image.png image.png 从源码分析来看,LLVM做这些操作跟objc_setPropertyobjc_getProperty的实现是契合的, 总得来说,如果取值的时候,是automic, 则需要objc_getProperty, 如果设置值的时候, 需要做内存的copy,retain, release操作,则需要objc_setProperty.

编码

image.png 通过看源码,会看到一些比较奇怪的符号,比如上图中,这些符号就是编码 可以通过@encode()函数得到所有类型的encode符号

char *buf1 = @encode(int **);
char *buf2 = @encode(struct key);
char *buf3 = @encode(Rectangle);

API

通过#import <objc/runtime.h>中的API获取类方法,实例方法

class_getInstanceMethod
class_getClassMethod
class_getMethodImplementation

image.png

image.png

class_getMethodImplementation探索,为什么我们有时候并没有实现一个方法,但是当调用class_getMethodImplementation返回却不为空呢?因为会发挥一个默认值。 image.png

扩展

image.png