OC对象的本质及分类
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)題。
- 上一篇: php 获取URL 各部分参数
- 下一篇: 正则表达式三种模式:贪婪模式、懒惰模式、