1.類的內(nèi)存的ro數(shù)據(jù)
還是先上代碼:
#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
上一章節(jié)OC底層4-類的探究分析(上)分析時(shí),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)
此時(shí)發(fā)現(xiàn) firstSubclass = LGTeacher出現(xiàn)了,我們項(xiàng)目中沒有做任何初始化,奇怪了?原因是這里類執(zhí)行了懶加載,至于懶加載我們后續(xù)文章在做分析,接下來我們還是繼續(xù)來看如何找到成員變量 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結(jié)構(gòu),繼續(xù)往下執(zhí)行
(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底層開發(fā)課程/1.iOS底層大師班/20210616-大師班-第4節(jié)課-類的原理分析上/20210616-大師班第4天-類的原理分析上/01--課堂代碼/004-類的結(jié)構(gòu)分析/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)
到這,我們已經(jīng)將LGPerson 成員變量和屬性都找出來了,
備注:
屬性&成員變量&實(shí)例變量的區(qū)別
成員變量:String、 int 、 double、 float、 char、 bool
屬性 = 帶下劃線成員變量 + setter + getter ?法
實(shí)例變量 : 特殊的成員變量 (類的實(shí)例化)
接下來查找類方法+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 、數(shù)據(jù)結(jié)構(gòu)的變化看一下這篇文章Objective-C 運(yùn)行時(shí)的改進(jìn)之?dāng)?shù)據(jù)結(jié)構(gòu)的變化
2.成員變量和屬性以及編碼
// 成員變量 vs 屬性 VS 實(shí)例變量
@interface LGPerson : NSObject
{
NSString *hobby; // 字符串
int a;
NSObject *objc; // 結(jié)構(gòu)體
}
@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轉(zhuǎn)換為底層源碼
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;
上面可以看出:屬性轉(zhuǎn)化為:帶下劃線成員變量 + setter + getter ?法
其中setter與getter方法代碼如下
截屏2021-06-20 下午9.42.02.png
發(fā)現(xiàn)屬性setter方法有objc_setProperty和self + OBJC_IVAR_ 內(nèi)存平移賦值兩種實(shí)現(xiàn)方式?
后面來分析,現(xiàn)在先來看下蘋果各種類型編碼都代表什么意思
截屏2021-06-20 下午9.55.40.png
可以通過蘋果的官方文檔來查看:
例如:nickName", "@16@0:8"
1.@:id
2.16: 占用內(nèi)存
- @:id
- 0:從0號位置開始
- ::SEL
- 8 :從8號位置開始
3.setter方法的底層原理
對objc_setProperty分析:
截屏2021-06-18 上午9.47.28.png
截屏2021-06-20 下午11.56.28.png
當(dāng)我們屬性為copy類型時(shí)候,會調(diào)用GetSetProperty的方法。
4.類方法存儲的API介紹
未完待續(xù)...



