OC底層5-類的探究分析(下)

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_tclass_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_setPropertyself + 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)存

  1. @:id
  2. 0:從0號位置開始
  3. ::SEL
  4. 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ù)...
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容