1.类的内存的ro数据
还是先上代码:
#import <Foundation/Foundation.h>
#import "LGPerson.h"
NS_ASSUME_NONNULL_BEGIN
@interface LGTeacher : LGPerson
@property (nonatomic, copy) NSString *hobby;
- (void)teacherSay;
@end
NS_ASSUME_NONNULL_END
#import "LGTeacher.h"
@implementation LGTeacher
- (instancetype)init{
if (self == [super init]) {
NSLog(@"我来了: %@",self);
return self;
}
return nil;
}
- (void)teacherSay{
NSLog(@"%s",__func__);
}
@end
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LGPerson : NSObject{
NSString *subject;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *hobby;
- (void)sayNB;
+ (void)say666;
@end
NS_ASSUME_NONNULL_END
#import "LGPerson.h"
@implementation LGPerson
- (instancetype)init{
if (self = [super init]) {
self.name = @"Cooci";
}
return self;
}
- (void)sayNB{
}
+ (void)say666{
}
@end
上一章节OC底层4-类的探究分析(上)分析时,LGPerson里面的成员变量 NSString *subject,类方法+say666还没有找到,先来打印下
(lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100004410 LGPerson
(lldb) p (class_data_bits_t *)0x0000000100004430
(class_data_bits_t *) $1 = 0x0000000100004430
(lldb) p $1->data()
(class_rw_t *) $2 = 0x000000010076dd60
(lldb) p *$2
(class_rw_t) $3 = {
flags = 2148007936
witness = 0
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4294984104
}
}
firstSubclass = nil
nextSiblingClass = NSUUID
}
(lldb)
这里还有个问题打印出class_rw_t里面firstSubclass = nil ,我们知道是有一个LGTeacher继承LGPerson,为什么会nil?接下来我们再来个东西,先打印下: p LGTeacher.class
(lldb) p LGTeacher.class
(Class) $4 = LGTeacher
(lldb) p $1->data()
(class_rw_t *) $5 = 0x000000010076dd60
(lldb) p *$5
(class_rw_t) $6 = {
flags = 2148007936
witness = 0
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4294984104
}
}
firstSubclass = LGTeacher
nextSiblingClass = NSUUID
}
(lldb)
此时发现 firstSubclass = LGTeacher出现了,我们项目中没有做任何初始化,奇怪了?原因是这里类执行了懒加载,至于懒加载我们后续文章在做分析,接下来我们还是继续来看如何找到成员变量 NSString *subject;
(lldb) p $6.ro()
(const class_ro_t *) $7 = 0x00000001000041a8
(lldb) p *$7
(const class_ro_t) $8 = {
flags = 0
instanceStart = 8
instanceSize = 32
reserved = 0
= {
ivarLayout = 0x0000000000000000
nonMetaclass = nil
}
name = {
std::__1::atomic<const char *> = "LGPerson" {
Value = 0x0000000100003ef8 "LGPerson"
}
}
baseMethodList = 0x00000001000041f0
baseProtocols = 0x0000000000000000
ivars = 0x0000000100004288
weakIvarLayout = 0x0000000000000000
baseProperties = 0x00000001000042f0
_swiftMetadataInitializer_NEVER_USE = {}
}
(lldb)
得到一个class_ro_t结构,继续往下执行
(lldb) p $8.ivars
(const ivar_list_t *const) $9 = 0x0000000100004288
(lldb) p *$9
(const ivar_list_t) $10 = {
entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 3)
}
(lldb) p $10.get(0)
(ivar_t) $11 = {
offset = 0x00000001000043a8
name = 0x0000000100003eae "subject"
type = 0x0000000100003f7f "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $10.get(1)
(ivar_t) $12 = {
offset = 0x00000001000043b0
name = 0x0000000100003eb6 "_name"
type = 0x0000000100003f7f "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $10.get(2)
(ivar_t) $13 = {
offset = 0x00000001000043b8
name = 0x0000000100003ebc "_hobby"
type = 0x0000000100003f7f "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $10.get(3)
Assertion failed: (i < count), function get, file /Users/fengjiefeng/Desktop/逻辑教育V14--iOS底层开发课程/1.iOS底层大师班/20210616-大师班-第4节课-类的原理分析上/20210616-大师班第4天-类的原理分析上/01--课堂代码/004-类的结构分析/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb)
到这,我们已经将LGPerson 成员变量和属性都找出来了,
备注:
属性&成员变量&实例变量的区别
成员变量:String、 int 、 double、 float、 char、 bool
属性 = 带下划线成员变量 + setter + getter ⽅法
实例变量 : 特殊的成员变量 (类的实例化)
接下来查找类方法+say666
KCObjcBuild was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) x/4gx LGPerson.class
0x100004410: 0x0000000100004438 0x0000000100354140
0x100004420: 0x000000010075e7f0 0x0002802800000003
(lldb) p/x 0x0000000100004438 & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x0000000100004438
(lldb) po 0x0000000100004438
LGPerson
(lldb) p/x (class_data_bits_t *)0x0000000100004458
(class_data_bits_t *) $3 = 0x0000000100004458
(lldb) p $3->data()
(class_rw_t *) $4 = 0x000000010075e790
(lldb) p *$4
(class_rw_t) $5 = {
flags = 2684878849
witness = 0
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4311956033
}
}
firstSubclass = nil
nextSiblingClass = 0x00007fff8d81bcd8
}
(lldb) p $5.methods()
(const method_array_t) $6 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100004360
}
arrayAndFlag = 4294984544
}
}
}
(lldb) p $6.list
(const method_list_t_authed_ptr<method_list_t>) $7 = {
ptr = 0x0000000100004360
}
(lldb) p $7.ptr
(method_list_t *const) $8 = 0x0000000100004360
(lldb) p *$8
(method_list_t) $9 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 1)
}
(lldb) p $9.get(0).big()
(method_t::big) $10 = {
name = "say666"
types = 0x0000000100003f77 "v16@0:8"
imp = 0x0000000100003e10 (KCObjcBuild`+[LGPerson say666])
}
(lldb)
对于class_rw_t、class_ro_t 、数据结构的变化看一下这篇文章Objective-C 运行时的改进之数据结构的变化
2.成员变量和属性以及编码
// 成员变量 vs 属性 VS 实例变量
@interface LGPerson : NSObject
{
NSString *hobby; // 字符串
int a;
NSObject *objc; // 结构体
}
@property (nonatomic, copy) NSString *nickName;
@property (atomic, copy) NSString *acnickName;
@property (nonatomic) NSString *nnickName;
@property (atomic) NSString *anickName;
@property (nonatomic, strong) NSString *name;
@property (atomic, strong) NSString *aname;
@end
@implementation LGPerson
@end
@interface LGTeacher : NSObject
@end
@implementation LGTeacher
@end
clang -rewrite-objc main.m -o main.cpp
将LGPerson转换为底层源码
extern "C" unsigned long OBJC_IVAR_$_LGPerson$_nickName;
extern "C" unsigned long OBJC_IVAR_$_LGPerson$_nnickName;
extern "C" unsigned long OBJC_IVAR_$_LGPerson$_anickName;
extern "C" unsigned long OBJC_IVAR_$_LGPerson$_name;
extern "C" unsigned long OBJC_IVAR_$_LGPerson$_aname;
struct LGPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *hobby;
int a;
NSObject *objc;
NSString *_nickName;
NSString *_acnickName;
NSString *_nnickName;
NSString *_anickName;
NSString *_name;
NSString *_aname;
};
// @property (nonatomic, copy) NSString *nickName;
// @property (atomic, copy) NSString *acnickName;
// @property (nonatomic) NSString *nnickName;
// @property (atomic) NSString *anickName;
上面可以看出:属性转化为:带下划线成员变量 + setter + getter ⽅法
其中setter与getter方法代码如下
截屏2021-06-20 下午9.42.02.png
发现属性setter方法有objc_setProperty和self + OBJC_IVAR_ 内存平移赋值两种实现方式?
后面来分析,现在先来看下苹果各种类型编码都代表什么意思
截屏2021-06-20 下午9.55.40.png
可以通过苹果的官方文档来查看:
例如:nickName", "@16@0:8"
1.@:id
2.16: 占用内存
- @:id
- 0:从0号位置开始
- ::SEL
- 8 :从8号位置开始
3.setter方法的底层原理
对objc_setProperty分析:
截屏2021-06-18 上午9.47.28.png
截屏2021-06-20 下午11.56.28.png
当我们属性为copy类型时候,会调用GetSetProperty的方法。
4.类方法存储的API介绍
未完待续...
网友评论