今天講的是OC語言相關(guān)類的東西版述,基礎(chǔ)語法那些就不講了遥巴,講下他的特別的地方。
也是根據(jù)印象寫的嫩痰,難免有所紕漏,希望大家指正
關(guān)鍵字部分:
assign
: 主要用于修飾基本數(shù)據(jù)類型窍箍,簡單賦值串纺,不更改引用計數(shù)。修飾的對象釋放后椰棘,指針的地址依舊存在纺棺,會造成野指針。在堆上容易造成崩潰邪狞。棧上的內(nèi)存系統(tǒng)會自動處理祷蝌。(關(guān)于堆棧會在內(nèi)存管理章節(jié)詳細(xì)說這一塊,可以簡單理解為因?yàn)榛緮?shù)據(jù)類型分配在棧中即可)
retain
: MRC中使用帆卓。釋放舊值巨朦,保留新值,并增加新值的引用計數(shù)剑令。
strong
:用于修飾強(qiáng)引用的屬性糊啡,釋放舊的對象,將舊的對象的值賦予新的對象吁津,并使引用計數(shù)+1
weak
:相當(dāng)于assign棚蓄,用于修飾弱引用的屬性,與assign不同的地方是腺毫,weak會在對象消失的時候自動把指針置為nil.不會增加引用計數(shù)
copy
:建立一個索引計數(shù)為1的對象癣疟,然后釋放舊的對象,一個對象發(fā)生變化不影響另一個對象潮酒。(copy只是淺復(fù)制睛挚,只復(fù)制指針地址,不會開辟新的內(nèi)存空間
@dynamic
: 告訴編譯器不自動生成setter getter方法
@synthesize
:如果屬性沒有手動實(shí)現(xiàn)setter和getter方法急黎,編譯器會自動加上這兩個方法
nonatomic
:禁止多線程扎狱,變量保護(hù),提高性能勃教。它比atomic快淤击,但也是線程不安全的。
atomic
: 修飾的對象會保證 setter 和 getter 的完整性故源,任何線程對其訪問都可以得到一個完整的初始化后的對象污抬。它比nonatomic安全,但不是絕對的線程安全,如多個線程調(diào)用set和get方法會導(dǎo)致獲得的對象值不同印机。絕對的線程安全可以用同步鎖@synchronizd.
類與對象
數(shù)據(jù)結(jié)構(gòu)
1.Class
struct objc_class {
struct objc_class *isa; // isa指針
struct objc_class *super_class; // 父類指針
const char *name; //類名
long version; //版本信息矢腻,默認(rèn)為0
long info; // 類信息,供運(yùn)行時使用的位標(biāo)識
long instance_size; //該類的實(shí)例變量大小
struct objc_ivar_list *ivars; // 該類的成員變量鏈表
#if defined(Release3CompatibilityBuild)
struct objc_method_list *methods; // 方法定義的鏈表
#else
struct objc_method_list **methodLists; // 方法定義的鏈表
#endif
struct objc_cache *cache; // 方法緩存
struct objc_protocol_list *protocols; // 協(xié)議鏈表
}
重點(diǎn)介紹下幾個屬性
- isa指針: 在oc中所有類對象本身也是一個對象射赛,這個對象的Class里面也有一個isa指針指向metaClass多柑。
- super_class:指向該類的父類,如果是最頂層的根類(NSObject或NSProxy)楣责,則super_class為NULL.(tip:之后會講講NSProxy的應(yīng)用場景)竣灌。
- cache: 用于方法列表的緩存。
2.object
struct objc-object {
Class isa ;
}
typedef struct objc_object *id;
isa 指針指向object的類秆麸,當(dāng)某個對象調(diào)用消息時初嘹,會通過該對象的isa指針找到這個實(shí)例對象的類,在類的方法列表及父類的方法列表中查找沮趣。
當(dāng)創(chuàng)建一個實(shí)例對象時削樊,分配的內(nèi)存包含了一個objc_object數(shù)據(jù)結(jié)構(gòu),然后是類的實(shí)例變量的數(shù)據(jù)兔毒。NSObject類的alloc和allocWithZone:方法會調(diào)用class_creatInstance來創(chuàng)建objc_object數(shù)據(jù)結(jié)構(gòu)漫贞。
3.cache
struct objc_cache {
unsigned int mask;
unsigned int occupied;
Method buckets[1];
}
- mask: 當(dāng)前能達(dá)到的最大的index(從0開始),所以緩存的size(total)是mask+1
- occupied:指定實(shí)際占用的緩存bucket的總數(shù)。因?yàn)閏ache是以散列表的形式存在的,所以會有空槽,occupied表示當(dāng)前被占用的數(shù)目罐栈。
- buckets: 指向method數(shù)據(jù)結(jié)構(gòu)指針的數(shù)組。這個數(shù)組可能包含不超過mask+1個元素谴蔑。需要注意的是指針可能是NULL,表示該緩存bucket沒有被占用,另外占用的bucket可能是不連續(xù)的龟梦,這個數(shù)組會隨著時間增長隐锭。
常見區(qū)分
4. id 與 NSObjct*
id: typedef struct objc_object *id , id 本質(zhì)上是一個指向結(jié)構(gòu)體struct_object的指針。關(guān)于這個對象的消息计贰,編譯器需要到運(yùn)行時才會確定钦睡,所以編譯器不會判斷對這個對象調(diào)用的消息進(jìn)行判斷。
NSObjcet: 編譯器會確切知道了該類的所有消息躁倒,向該對象發(fā)送NSObject沒有聲明的消息的時候編譯器會報錯荞怒。
5.id與instancetype
instancetype:使方法的返回類型為所在類的類型。
id和instancetype的區(qū)別
- id在編譯期無法判斷對象的真實(shí)類型
- instancetype返回的對象調(diào)用方法時編譯器會進(jìn)行類型檢查秧秉,如果賦值給其他對象會報警告
- id可以用來定義變量褐桌,也可以作為返回值,形參象迎,instancetype只能用于返回值
6.實(shí)例對象荧嵌,類對象以及他們的isa指針以及meta-class:
- 實(shí)例對象objc_object的isa指針指向objc_class
- 類對象 objc_class的isa指針指向自身的meta-class
- meta-class的isa指針指向NSObject的meta-class,NSObject的meta-class指向自身
7. [self class] [super class]調(diào)用分析:
查看class的調(diào)用:
- (Class)class{
return objcet_getClass(self);
}
super
調(diào)用方法時實(shí)質(zhì)是調(diào)用:
objc_msgSendSuper(struct objc_super * _Nonull super, SEL _Nonnull op, ...)
可知super
是一個指向 objc_super結(jié)構(gòu)體 的指針
查看objc_super
objc_msgSendSuper函數(shù)可轉(zhuǎn)換為:
objc_msgSendSuper((objc_super){(id)self,(id)class_getSuperClass(objc_getClass(self))},op)
顯然receiver就是實(shí)例對象,super_class為self的父類啦撮。所以調(diào)用super
的時候傳遞的對象也就是receiver為self恋技。
所以 NSStringFromClass([self class]) 和NSStringFromClass([super class]) 返回的值是一樣的。
面試相關(guān)
- 一個OC對象占用多少內(nèi)存
系統(tǒng)分配了16個字節(jié)給NSObject對象(通過malloc_size函數(shù)獲得),但NSObject對象內(nèi)部只使用了8個字節(jié)的空間(64位環(huán)境下,通過class_getInstanceSize獲得)