咱们的Xcode其实很强大,集成了不少牛逼的工具,clang就是其中之一,咱们可使用如下的命令对.m文件进行编译咱们就能够看到咱们的OC 编译到底层的C或者C++究竟是怎么样的c++
我这里的例子是使用的是main.m 文件,各位能够根据具体SDK的文件路径和须要编译的文件去编译研究
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m //模拟器的使用命令
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk main.m //真机的使用命令
复制代码
咱们编译完看到的就是一个C++的结构体,没错就是一个objec_class的结构体,他的结构体长成这个样子: objective-c
在上面我有说到对象在实例化时返回的就是一个isa,并且就干了一件事情,就是把咱们实例化出来的对象跟类进行绑定。那么isa就是是个啥玩意?且看如下分解:数组
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;//类对象
uintptr_t bits;//位域
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
复制代码
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \表示是否对 isa 指针开启指针优化
uintptr_t has_assoc : 1; \是否有关联对象
uintptr_t has_cxx_dtor : 1; \否有 C++ 或者 Objc 的析构器
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \存储类指针的值
uintptr_t magic : 6; \用于调试器判断当前对象是真的对象仍是没有初始化的空间
uintptr_t weakly_referenced : 1; \是否被指向或者曾经指向一个 ARC 的弱变量
uintptr_t deallocating : 1; \是否正在释放
uintptr_t has_sidetable_rc : 1; \当对象引用技术大于 10 时,则须要借用该变量存储进位
uintptr_t extra_rc : 19\当表示该对象的引用计数值,其实是引用计数值减 1,当大于10时须要借用上面的标志位
复制代码
这是一个宏定义的位域,后面的数字表示占有的位数。其实就是对isa进行了优化,把一个8字节的空间进行了高效使用,从而存储了更多的东西,如刚刚的cls 就存储在shiftcls中。缓存
相信有不少人已经有所了解,可是说到isa,我仍是介绍下走位bash
字面意思就是缓存,事实上Runtime进行消息查找的时候若是每次查完就直接扔了很浪费,哪些常常用的或者最近查找过的方法会进行缓存,这样就提升了方法调用的效率。具体介绍能够参考我以前写过的关于cache_t的分析的文章 https://juejin.im/post/5e1469f6e51d4541657776b4
app
不知道咱们是否是很好奇,既然对象实例化以后啥都没有那么我写的那些属性、方法都在哪呢?难道在类里面吗? 还真是,不过这个类是相对的,类是对象的类,元类是类的类,以此类推。bits里面就存了对象的属性、实例化方法(注意是实例化方法,类方法在元类的bits里面)ide
咱们看到了bits.data()返回的是一个class_rw_t *结构体指针,说明了这个bits里面存的就是这个结构体数据。函数
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
复制代码
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#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;
}
};
复制代码
咱们来先自定义一个类,配置好objc的源码,用LLDB调试看看内存中的数据工具
获取bits中的数据 post
ro中的数据
读属性,nickName 已经在数组中的第一个,总数也是一个(咱们的类中也只写了一个)。
读方法,属性对应的set、get方法,咱们本身定义的一个实例化方以及一个c++的函数
在这些底层的研究过程当中,思考苹果开发工程师的开发思路和设计思想是一件很享受的事情,弄清楚他们怎样作到让这个代码的效率如此之高对本身的开发水平提升有很好地帮助,用C++ 写过游戏的朋友估计体验比较深入,游戏全部的都是本身实现,除了场景以及渲染用到的游戏引擎。
有兴趣一块儿交流的朋友,能够加 QQ:578200388