一、 对象的本质
对象的本质是
结构体
二、探索方式clang
/ xcrun
2.1 什么是clang
Clang
是一个C语言
、C++
、Objective-C
语言的轻量级编译器
。Clang
是一个由Apple
主导编写,基于LLVM
的C/C++/Objective-C编译器
2.2 clang
命令
-
clang -rewrite-objc xx.m -o xx.cpp
把目标文件编译成c++文件 [xx.m
中的xx
为目标文件名,xx.cpp
中的xx
为编译后文件名] -
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulatorxxx.sdk xx.m -o xx.cpp
把目标文件编译成c++文件(当出现某些库找不到时使用,比如UIKit
)[iPhoneSimulatorxxx.sdk
中的xxx
为当前你电脑里面的模拟器版本]
2.3 什么是xcrun
-
xcode
安装的时候会自动安装xcrun
命令 -
xcrun
命令在clang
的基础上进行了 一些封装,相对来说更好用一些
2.4 xcrun
命令
-
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc xx.m -o xx.cpp
把目标文件编译成c++文件 [xx.m
中的xx
为目标文件名,xx.cpp
中的xx
为编译后文件名](模拟器版) -
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xx.m -o xx.cpp
[xx.m
中的xx
为目标文件名,xx.cpp
中的xx
为编译后文件名](手机版)
二、探索
2.1 在main.h
中创建一个对象GomuPerson
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here..
GomuPerson *person = [GomuPerson alloc];
}
return 0;
}
2.2 用clang
生成c++
文件
clang -rewrite-objc main.m -o mian.cpp
-
OC
的底层是C
,C++
的底层也是C
,所以我们可以进一步把OC
编译成C++
(重构) - 编译会出现很多警告,那是因为我们没有指定处理器架构,可以忽略
2.3 打开生成好的main.cpp
2.4 寻找探索目标GomuPerson
,全局搜索🔍
#ifndef _REWRITER_typedef_GomuPerson
#define _REWRITER_typedef_GomuPerson
typedef struct objc_object GomuPerson;
typedef struct {} _objc_exc_GomuPerson;
#endif
struct GomuPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
};
-
typedef struct objc_object GomuPerson
从这行代码我们不难看出,GomuPerson
就是objc_object
类型的结构体
-
GomuPerson_IMPL
继承了NSObject_IMPL
2.4 我们看看GomuPerson
的父类NSObject
是否也是结构体,全局搜索NSObject_IMPL
#ifndef _REWRITER_typedef_NSObject
#define _REWRITER_typedef_NSObject
typedef struct objc_object NSObject;
typedef struct {} _objc_exc_NSObject;
#endif
struct NSObject_IMPL {
Class isa;
};
-
NSObject
也是objc_object
类型的结构体
-
isa
是NSObject
的属性 -
GomuPerson_IMPL
继承了NSObject_IMPL
,所以也就继承了它的属性isa
三、拓展知识
3.1 用clang
命令把GomuPerson.m
编译成GomuPerson.cpp
3.2 全局搜索GomuPerson
,找到GomuPerson_IMPL
struct GomuPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString * _Nonnull _name;
};
- 发现除了
NSObject_IVARS
,还多了我们在GomuPerson .h
中定义的属性name
3.3 往下滑一点会发现属性的set
,get
的现实方法
-
_I_GomuPerson_name
就是属性name
的get
方法 -
_I_GomuPerson_name
就是属性name
的set
方法 - 系统编译的时候,原来是这样初始化属性的
set
,get
方法的。 -
_I_GomuPerson_name
中发现objc_setProperty
3.3 objc4
源码中找objc_setProperty
void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
{
bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
bool mutableCopy = (shouldCopy == MUTABLE_COPY);
reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}
- 初始化
set
方法的时候,属性名都转成字符串,以SEL
的形式传入objc_setProperty
,不同的属性都用相同的方法,通过SEL
区分,这就是工厂设计。
3.4 进入reallySetProperty
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
//: 对新值的retain
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
//: 对就值的release
objc_release(oldValue);
}
-
reallySetProperty
方法中,会对属性新赋的值
进行retain
,老的值进行release