日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OC对象的本质及分类

發(fā)布時(shí)間:2025/3/15 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OC对象的本质及分类 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Object-C的底層都是通過(guò)C/C++來(lái)實(shí)現(xiàn)的,所以O(shè)C中的對(duì)象也會(huì)轉(zhuǎn)化成C/C++中的某一個(gè)數(shù)據(jù)結(jié)構(gòu),

我們?cè)诮K端里通過(guò)指令

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main_arm64.cpp

將oc代碼轉(zhuǎn)化為c++代碼,我們可以看到NSObject的底層結(jié)構(gòu)是:

struct NSObject_IMPL {Class isa; };

Class是一個(gè)指向?qū)ο蟮慕Y(jié)構(gòu)體指針

typedef struct objc_class *Class;

?

所以NSObject最終會(huì)轉(zhuǎn)化成一個(gè)結(jié)構(gòu)體,內(nèi)部只有一個(gè)指向?qū)ο蟮慕Y(jié)構(gòu)體指針

所以NSObject對(duì)象只會(huì)使用8個(gè)字節(jié)的內(nèi)存空間來(lái)存儲(chǔ)指針(當(dāng)然 實(shí)際上給它分配了16個(gè)內(nèi)存空間)

NSLog(@"%zd",class_getInstanceSize([NSObject class])); //實(shí)例對(duì)象的成員所占用的大小8 (實(shí)際使用的) NSLog(@"%zd",malloc_size((__bridge const void *)(obj))); //整個(gè)結(jié)構(gòu)體占用的是16(實(shí)際分配的) 同時(shí),通過(guò)閱讀源碼我們得知,當(dāng)創(chuàng)建的對(duì)象分配的內(nèi)存空間小于16個(gè)字節(jié)的時(shí)候 系統(tǒng)都會(huì)分配16個(gè)字節(jié)的空間 這屬于是蘋(píng)果規(guī)定。 size_t instanceSize(size_t extraBytes) {size_t size = alignedInstanceSize() + extraBytes;// CF requires all objects be at least 16 bytes.if (size < 16) size = 16;return size;}

??

如果有一個(gè)student類(lèi)繼承了object并且有倆個(gè)int屬性,那么student所占用的內(nèi)存是多少呢?

student實(shí)際占用內(nèi)存為16字節(jié),系統(tǒng)分配的內(nèi)存也是16字節(jié)。

?

假設(shè)有個(gè)person繼承NSObject,student繼承person,那么person和student各占用多少內(nèi)存呢?

?

最終通過(guò)打印我們發(fā)現(xiàn),person,實(shí)際占用16,系統(tǒng)分配16,student實(shí)際占用16,系統(tǒng)分配16.

為什么?person實(shí)際占用16??int 4個(gè)字節(jié) isa 8個(gè)字節(jié) 應(yīng)該是12個(gè)字節(jié)啊?這就涉及到了前面寫(xiě)到的結(jié)構(gòu)體內(nèi)存對(duì)齊了。

?

對(duì)象的分類(lèi)

oc中的對(duì)象主要可以分為三類(lèi):

1.實(shí)例對(duì)象,就是通過(guò)類(lèi)alloc出來(lái)的對(duì)象,每次調(diào)用alloc都會(huì)生成一個(gè)新的實(shí)例對(duì)象

?

object1 和 object2 就是兩個(gè)實(shí)例對(duì)象

實(shí)例對(duì)象在內(nèi)存中存儲(chǔ)的信息包括:

1、isa指針 (其實(shí)isa也算是對(duì)象的成員變量 ?也就是說(shuō)實(shí)例對(duì)象內(nèi)部只包含自己的成員變量)

2、其他成員變量(這里是存儲(chǔ)成員變量的具體值)

?

?

2、類(lèi)對(duì)象(class)?

objectClass1-5 都是NSObject的類(lèi)對(duì)象 ,因?yàn)?span style="color:#0000ff;">每個(gè)類(lèi)在內(nèi)存中有且只有一個(gè)類(lèi)對(duì)象 ?所以上面五個(gè)類(lèi)對(duì)象其實(shí)是同一個(gè)對(duì)象

類(lèi)對(duì)象在內(nèi)存中存儲(chǔ)的信息主要有:

1、isa指針

2、superclass指針

3、成員變量(這里的成員變量只是描述性的 ?比如有哪些變量 是什么類(lèi)型的 ?并不是實(shí)例對(duì)象的具體變量值)?

4、類(lèi)的對(duì)象方法(-號(hào)開(kāi)頭的方法)

5、類(lèi)的協(xié)議信息和屬性信息

類(lèi)對(duì)象的本質(zhì)結(jié)構(gòu)↓↓↓

?

3、元類(lèi)對(duì)象(meta-class)

objectMetaClass就是NSObject的元類(lèi)對(duì)象,元類(lèi)對(duì)象也是每個(gè)類(lèi)在內(nèi)存中有且只有一個(gè),元類(lèi)對(duì)象和類(lèi)對(duì)象在結(jié)構(gòu)上非常相似。

元類(lèi)對(duì)象在內(nèi)存中春初的主要信息有:

1、isa指針

2、superclass指針

3、類(lèi)方法(+號(hào)開(kāi)頭的方法)?

?

我們看到通過(guò)object_getclass方法即能獲得元類(lèi)對(duì)象 也能獲得類(lèi)對(duì)象 ?通過(guò)查看源碼我們可以得知object_getclass會(huì)判斷傳進(jìn)來(lái)的參數(shù)是類(lèi)對(duì)象還是實(shí)例對(duì)象 ?如果是實(shí)例對(duì)象則返回類(lèi)對(duì)象 ?如果傳進(jìn)來(lái)的是類(lèi)對(duì)象則返回元類(lèi)對(duì)象

我們也可以通過(guò)下面的函數(shù)來(lái)判斷對(duì)象是不是元類(lèi)對(duì)象

?

也就是說(shuō)通過(guò)alloc創(chuàng)建的是實(shí)例對(duì)象 ?通過(guò)object_getclass(類(lèi)對(duì)象)創(chuàng)建的是元類(lèi)對(duì)象 ?其他對(duì)象則是類(lèi)對(duì)象 ?但是類(lèi)對(duì)象和元類(lèi)對(duì)象有且只有一個(gè)

?

三類(lèi)對(duì)象中 都含有isa指針,那么這個(gè)isa指針指向什么?

實(shí)例對(duì)象的isa指向類(lèi)對(duì)象 ?類(lèi)對(duì)象的isa指向元類(lèi)對(duì)象 ?元類(lèi)對(duì)象的isa指向基類(lèi)的元類(lèi)對(duì)象

正是通過(guò)isa指針 才讓三種對(duì)象產(chǎn)生關(guān)聯(lián)

比如說(shuō),一個(gè)實(shí)例對(duì)象想調(diào)用對(duì)象方法 ?但是對(duì)象方法存放在類(lèi)對(duì)象中 ?那么就是通過(guò)isa找到對(duì)象方法再進(jìn)行調(diào)用 ??

同理 ?當(dāng)調(diào)用類(lèi)方法的時(shí)候 ?類(lèi)方法是存放在元類(lèi)對(duì)象中的 ?類(lèi)對(duì)象通過(guò)isa指針找到元類(lèi)對(duì)象 讀取類(lèi)方法列表中的類(lèi)方法進(jìn)行調(diào)用

?

superclass指針

在類(lèi)對(duì)象和元類(lèi)對(duì)象中都有一個(gè)superclass指針,其實(shí)這兩種對(duì)象中的superclass指針作用類(lèi)似,都是指向父類(lèi)對(duì)象

類(lèi)對(duì)象中的superclass指針:

比如現(xiàn)在有一個(gè)Person對(duì)象繼承自NSObject ?有一個(gè)Student繼承自Person ?當(dāng)studen的實(shí)例對(duì)象調(diào)用對(duì)象方法的時(shí)候,首先實(shí)例對(duì)象會(huì)根據(jù)自己的isa指針去類(lèi)對(duì)象中找有沒(méi)有對(duì)應(yīng)的方法 ?沒(méi)有的話(huà)類(lèi)對(duì)象會(huì)根據(jù)自己的superclass指針去父類(lèi)的類(lèi)對(duì)象中去查找(也就是student的類(lèi)對(duì)象根據(jù)superclass指針去Person的類(lèi)對(duì)象中去查找有沒(méi)有對(duì)應(yīng)的對(duì)象方法 ?再?zèng)]有的話(huà)Person的類(lèi)對(duì)象會(huì)根據(jù)自己的superclass指針去NSObject的類(lèi)對(duì)象中去尋找 尋找到基類(lèi)在沒(méi)有對(duì)應(yīng)方法的話(huà)就會(huì)報(bào)方法找不到的錯(cuò)誤)

?

而元類(lèi)對(duì)象中的superclass指針也是指引類(lèi)對(duì)象去父類(lèi)對(duì)象中尋找對(duì)應(yīng)的類(lèi)方法:

按照上面的例子,Student這個(gè)類(lèi) 想調(diào)用一個(gè)類(lèi)方法,首先是Student的類(lèi)對(duì)象 根據(jù)isa指針去Student的元類(lèi)對(duì)象中查找有沒(méi)有對(duì)應(yīng)的類(lèi)方法 ?沒(méi)有的話(huà)Student的元類(lèi)對(duì)象會(huì)根據(jù)自己的superclass指針去父類(lèi)的元類(lèi)對(duì)象(也就是Person的元類(lèi)對(duì)象)中查找有沒(méi)有對(duì)應(yīng)的類(lèi)方法,在沒(méi)有的話(huà)Person的元類(lèi)對(duì)象再根據(jù)自己的superclass指針去NSObject的元類(lèi)對(duì)象中尋找 有的話(huà)進(jìn)行調(diào)用 沒(méi)有的話(huà)NSObject的元類(lèi)對(duì)象會(huì)根據(jù)superclass指針去NSObject的類(lèi)對(duì)象中去尋找是否有相同名稱(chēng)的對(duì)象方法(這個(gè)地方下面會(huì)具體講到為什么基類(lèi)的superclass指針會(huì)指向?qū)?yīng)的類(lèi)對(duì)象)

?

?

?

?

關(guān)于上面提到的為什么基類(lèi)的superclass指針為什么在找不到方法的時(shí)候會(huì)指向基類(lèi)的類(lèi)對(duì)象 也就是為什么沒(méi)有找到對(duì)應(yīng)的類(lèi)方法的情況下卻可以調(diào)用同名對(duì)象方法?

關(guān)于這一點(diǎn)我們通過(guò)代碼來(lái)驗(yàn)證:

首先我們新建一個(gè)NSObject的分類(lèi),在.h文件中聲明一個(gè)test的類(lèi)方法,但在.m文件中并未實(shí)現(xiàn)這個(gè)類(lèi)方法 ?而是實(shí)現(xiàn)了同名的對(duì)象方法()

#import "NSObject+Test.h"@implementation NSObject (Test)//+ (void)test //{ // NSLog(@"+[NSObject test] - %p", self); //}- (void)test {NSLog(@"-[NSObject test] - %p", self); }@end

我們調(diào)用類(lèi)方法發(fā)現(xiàn),及時(shí)沒(méi)有對(duì)應(yīng)的類(lèi)方法,程序也可以正常運(yùn)行,并且成功調(diào)用了同名的對(duì)象方法:

?

假如我們?cè)趍文件沒(méi)有實(shí)現(xiàn)同名test的對(duì)象方法,那么程序會(huì)報(bào)錯(cuò)的:

+[NSObject test]: unrecognized selector sent to class 0x7fffaddd7140

?

關(guān)于在h文件中有類(lèi)方法的聲明,這個(gè)是沒(méi)有影響的 因?yàn)闆](méi)有這個(gè)聲明的話(huà)程序根本跑不起來(lái) ?我們關(guān)注的點(diǎn)是基類(lèi)的superclass指針為什么在找不到方法的時(shí)候會(huì)指向基類(lèi)的類(lèi)對(duì)象尋找同名的對(duì)象方法 ?

比如我們?cè)趆文件中聲明了test的對(duì)象方法 ?m文件沒(méi)有實(shí)現(xiàn)test方法 同樣會(huì)報(bào)unrecognized錯(cuò) ?這就是因?yàn)榛?lèi)的對(duì)象方法中找不到方法后直接返回空值 ?而不是像類(lèi)方法一樣從元類(lèi)對(duì)象找不到再去到類(lèi)對(duì)象找同名對(duì)象方法

?

?

關(guān)于基類(lèi)的superclass指針為什么在找不到方法的時(shí)候會(huì)指向基類(lèi)的類(lèi)對(duì)象,這是因?yàn)閛c在調(diào)用方法的時(shí)候?qū)嶋H上是轉(zhuǎn)換為c/c++去底層實(shí)現(xiàn)的 ?但是c/c++的底層實(shí)現(xiàn)并沒(méi)有區(qū)分類(lèi)方法還是對(duì)象方法 也就是沒(méi)有區(qū)分+-號(hào)

比如

[NSObject test];

實(shí)際上是轉(zhuǎn)換為了

objc_msgSend([NSObject class], @selector(test))

沒(méi)有區(qū)分+-號(hào) ?所以在基類(lèi)元類(lèi)對(duì)象沒(méi)有找到對(duì)應(yīng)的類(lèi)方法后回去基類(lèi)的類(lèi)對(duì)象中查看是否有同名的對(duì)象方法 ?有的話(huà)就調(diào)用 ?再?zèng)]有的話(huà)就報(bào)錯(cuò)了

?

?

?

?

?

?

?

NSObject本質(zhì)揭秘

查看OC對(duì)象占用字節(jié)數(shù)

?

轉(zhuǎn)載于:https://www.cnblogs.com/gaoxiaoniu/p/10685238.html

總結(jié)

以上是生活随笔為你收集整理的OC对象的本质及分类的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。