struct class_rw_t {
...
...
//成员变量获取方法
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
}
return v.get<const class_ro_t *>(&ro_or_rw_ext);
}
....
//方法获取方法
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
}
}
//属性获取方法
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
}
}
//协议获取方法
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
}
}
};
写一个基本类
- 有属性、成员变量、实例变量
- 文件.m -> .cpp 文件指令
- clang -rewrite-objc main.m -o main.cpp
- 属性通过编译之后会变成带
“_”的成员变量,同时会自动生成响应的set和get方法
static NSString * _I_LGPerson_nickName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_nickName)); }
static void _I_LGPerson_setNickName_(LGPerson * self, SEL _cmd, NSString *nickName) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LGPerson, _nickName), (id)nickName, 0, 1); }
static NSString * _I_LGPerson_nnickName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_nnickName)); }
static void _I_LGPerson_setNnickName_(LGPerson * self, SEL _cmd, NSString *nnickName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_nnickName)) = nnickName; }
- get:是通过指针的偏移获取获取值得
- set: 是调用了 objc_setProperty 方法完成、或者内存偏移赋值完成。
类型与编码
- 在我们找方法中最后打印了一个 type "@16@0:8"
(lldb) p $6.get(0).big()
(method_t::big) $7 = {
name = "hobby"
types = 0x0000000100003f53 "@16@0:8"
imp = 0x0000000100003dc0 (KCObjcBuild`-[LGPerson hobby])
}
-
- (NSString *)hobby;这个方法的编码 为 "@16@0:8" -
编码类型转化
- @-> id 指针 刚好对应了 (NSString *)
- 方法中默认的有两个隐形参数 (LGPerson * self, SEL _cmd)
- LGPerson * 对应了第二个 @
- SEL 对应了 :
-
所以如果将方法写全了应该是
- (NSString *)hobby:(LGPerson *)self sel:(SEL)cmd
-
16 : 表示这个方法,参数所占用总内存大小
-
0 : 表示第一个参数从0位置开始
-
8 : 表示第二个参数从8位置开始
-
- (void)setNickName:(NSString *)nickName -
{(struct objc_selector *)"setNickName:", "v24@0:8@16", (void *)_I_LGPerson_setNickName_},- v - void
- @ - LGPerson *
- : - SEL
- @ - NSString *
- 占用 24字节
- self 0 开始
- cmd 8 开始
- nickName 16 开始
-
setName -> objc_setProperty , objc_setProperty是set方法的抽取封装的基类的方法。
-
利用的时依赖倒置原则的设计模式完成的对set方法的封装
加载流程
- 1
-
- 编译的时候在加载 ivars 成员变量时,利用 SEL ——> imp 设置方法的地址。(未实现)
-
- 调用的时候调用 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); } ------------------ - 对旧值和新值得处理,以及对内存空间的处理。 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; newValue = objc_retain(newValue); } if (!atomic) { oldValue = *slot; *slot = newValue; } else { spinlock_t& slotlock = PropertyLocks[slot]; slotlock.lock(); oldValue = *slot; *slot = newValue; slotlock.unlock(); } objc_release(oldValue); } -
- LLVM 编译 getSetPropertyFn() 创建一个 objc_setProperty 方法
- GetPropertySetFunction -> getSetPropertyFn
-
case GetSetProperty 或 case PropertyImplStrategy::SetPropertyAndExpressionGet: {
-
switch (strategy.getKind()) 由 stategy.getKind()
-
找到这个类型的赋值的地方
- 找到初始化方法
- 结论是copy