OC基礎(chǔ)知識(shí)

OC中內(nèi)存分為五大區(qū)域

棧:存儲(chǔ)局部變量和指針
堆:創(chuàng)建對象
BSS:存儲(chǔ)未初始化的全局變量和靜態(tài)變量
數(shù)據(jù)段(常量區(qū)):存儲(chǔ)已經(jīng)初始化的全局變量、靜態(tài)變量、常量數(shù)據(jù)
代碼段:存儲(chǔ)程序的代碼

類加載

當(dāng)類被第一次加載的時(shí)候,會(huì)將類的代碼存儲(chǔ)到代碼段中,這個(gè)過程叫類加載。
只有第一次訪問的時(shí)候,才有類加載。
一旦類被加載到程序中,直到程序結(jié)束的時(shí)候才會(huì)被回收

創(chuàng)建對象

[[NSObject alloc] init];
alloc分配內(nèi)存 init初始化

NSObject.+alloc 

struct obj_layout {
  NSUInteger retained;
}

+ (id) alloc {
    int size = sizeof(struct obj_layout);
    struct obj_layout *p = (struct obj_layout *)calloc(1, size);
    return (id)(p + 1);
}

銷毀對象

NSObject.release中,首先調(diào)用NSDecrementExtraRefCountWasZero使retrain-1。如果retrainCount == 0,調(diào)用release方法釋放內(nèi)存

NSObject.dealloc
釋放內(nèi)存

GNUstep

alloc類方法通過 struct obj_layout中對retrained整數(shù)來保存引用記數(shù),并將其寫入對象內(nèi)存頭部,將該對象內(nèi)存塊全部置0后返回

也就是,一個(gè)對象的引用記數(shù),放在這個(gè)類地址的最前面。

apple

使用一個(gè)散列表保存所有的引用記數(shù)。將對象的地址映射到散列表中。

autorelease

autorelease會(huì)在超過對象的作用域之后,自動(dòng)調(diào)用對象的release方法(記數(shù)-1。如果記數(shù)==0,調(diào)用dealloc方法)

GNUstep中autorelease的實(shí)現(xiàn)

[obj autorelease]方法的原理就是把對象添加到NSAutoreleasePool中

[NSAutoreleasePool drain]就是調(diào)用填入的所有對象的release方法

apple的實(shí)現(xiàn)

RunLoop和線程

在iOS開發(fā)中,會(huì)遇到兩個(gè)線程對象:pthread_t 和 NSThread,NSThread只是對pthread的封裝,兩者肯定是一一對應(yīng)的,我們可以通過pthread_main_thread_np()或者 [NSThread mainThread]來獲取主線程,也可以通過pthread_self() [NSThread currentThread]來獲取當(dāng)前的線程。

和runloop相關(guān)的有5個(gè)類,分別是
NSDefaultRunLoopMode:app默認(rèn)的mode,通常主線程是在這個(gè)mode下運(yùn)行的
UITrackingRunLoopMode:界面跟蹤mode。用于scorllview追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受影響
UIInitializationRunLoop:剛啟動(dòng)時(shí)app進(jìn)入第一個(gè)mode,啟動(dòng)完成就不再使用
GSRunLoopReceiveRunLoopMode:接受系統(tǒng)時(shí)間的內(nèi)部mode,繪圖服務(wù),通常用不到
NSRunLoopCommonModes:這是一個(gè)占位用的mode,不是一種真的mode

ARC

OC為了處理對象,將變量類型定義為id類型和各種對象類型
對象類型就是指向NSObject這樣的OC指針(NSObject
id類型用于隱藏對象類型的類名。相當(dāng)于C語言中的void

所有權(quán)修飾符

所有權(quán)修飾符一種有4種
__strong
__weak
__unsafe_unretained
__autoreleasing

__strong

__strong是id類型和對象類型默認(rèn)的所有權(quán)修飾符
id object = [NSObject new]等價(jià)于 id __strong object = [NSObject new];

強(qiáng)引用的變量,在超過變量作用域時(shí),會(huì)自動(dòng)釋放。

{
        id object = [NSObject new]
}
超過作用于自動(dòng)釋放

__weak
oc使用引用記數(shù),因此會(huì)出現(xiàn)循環(huán)引用的問題。__weak就是為了解決循環(huán)引用的問題。
下面的例子會(huì)出現(xiàn)循環(huán)引用

id test0 = [Test new];
id test1 = [Test new];
test0.myObj = test1
test1.myObj = test0

持有某對象的若引用時(shí),如果該對象被廢棄,此弱引用自動(dòng)失效,并被置為nil

__unsafe_unretrained

__unsafe_unretrained不會(huì)持有對象(類似弱引用),但是指向?qū)ο蟊会尫艜r(shí),不會(huì)自動(dòng)指向nil,還是會(huì)指向原來的地址,所以會(huì)導(dǎo)致野指針。
一般不使用__unsafe_unretrained

__autoreleasing

使用ARC的時(shí)候,不能直接使用autorelease方法,但是可以使用__autoreleaseing權(quán)限修飾符
ARC無效的時(shí)候的寫法

NSAutoreleasePool *pool = [NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease]
[pool drain];

ARC有效的時(shí)候的寫法

@autoreleasepool {
        id __autoreleasing obj = [[NSObject alloc] init];
}

編譯器會(huì)自動(dòng)檢查方法名是否以alloc/new/copy/mutableCopy開始,如果不是則自動(dòng)將返回值注冊到autoreleasepool。

ARC下的內(nèi)存管理規(guī)則

不能使用retain/release/retainCount/autorelease

不能使用NSAllocateObject/NSDeallocateObject

必須遵守內(nèi)存管理的方法命名

alloc
new
copy
mutableCopy
以上述名稱開始的方法在返回對象時(shí),必須返回給調(diào)用放應(yīng)當(dāng)持有的對象
ARC追加了一條
init方法必須是實(shí)例方法。返回的對象應(yīng)當(dāng)是id類型、方法聲明的對象類型、或者是該類型的父類或子類

不要顯式調(diào)用dealloc

使用@autoreleasepool代替NSAutoreleasePool

不能使用區(qū)域(NSZone)

對象類型變量不能作為C語言結(jié)構(gòu)體成員

void*和id之間轉(zhuǎn)換,必須強(qiáng)制轉(zhuǎn)換

盡量不要使用這種轉(zhuǎn)換方式,ARC不推薦
ARC下面的三種轉(zhuǎn)換方式

id obj = [[NSObject alloc] init];
void *p = (__bridge void*)obj;
id o = (__bridge id)p
這種轉(zhuǎn)換類似于 __unsade_unretained。對象釋放不會(huì)置為nil,所以很容易出現(xiàn)野指針
id obj = [[NSObject alloc]init];
void *p = (__bridge_retrained void*)obj
對象引用記數(shù)+1,相當(dāng)于retain
相當(dāng)于
id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void*)obj
id obj = (__bridge_transfer id)p
相當(dāng)于
id obj = (id)p
[obj retain];
[(id)p release]

屬性

屬性和所有權(quán)修飾符對應(yīng)
assign __unsade_unretained
copy __strong (賦值的是被復(fù)制的對象)
retain __strong
strong __strong
unsafe_unretained __unsafe_unretained
weak __weak

copy不是簡單的賦值,他的賦值是通過NSCopying接口的copyWithZone方法生成的對象,然后賦值。
id *類型默認(rèn)是autorelease,因此可以顯式的使用_strong
動(dòng)態(tài)數(shù)組(id *)中使用操作符和靜態(tài)數(shù)組(id[])不一樣,需要手動(dòng)釋放內(nèi)存。
因?yàn)樵陟o態(tài)數(shù)組中,編譯器能夠根據(jù)變量的作用域自動(dòng)插入釋放內(nèi)存的代碼。但是編譯器不能確定數(shù)組的生命周期,所以動(dòng)態(tài)數(shù)組需要按照下面的方式釋放

for (NSInteger i = 0; i < num; i++) {
        array[i] = nil; 
}

free(array)

類的成員變量和屬性

類的成員變量

@interface ViewController : UIViewController
{
    //成員變量
    NSArray *array1;
}

類的屬性

@property (nonatomic,strong) NSArray *array2;

類的屬性會(huì)自動(dòng)創(chuàng)建一個(gè)帶下劃線的成員變量,并且會(huì)給這個(gè)成員變量創(chuàng)建getter和setter方法。

ARC的實(shí)現(xiàn)

__strong的實(shí)現(xiàn)

id __strong obj = [[NSObject alloc] init];

編譯器會(huì)自動(dòng)插入釋放代碼,如下

id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj)

__weak的實(shí)現(xiàn)

{
        id __weak obj1 = obj;
}

等價(jià)于

id obj1
objc_initWeak(&obj1, obj);
objc_destoryWeak(&obj1);

等價(jià)于

id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
objc_storeWeak(&obj1,0);

oc會(huì)維護(hù)一張weak表,key是對象的地址,value是帶有weak變量的地址。
objc_storeWeak(&obj1, obj)把對象的地址作為key,變量的地址作為value存放到weak表里面。
objc_storeWeak(&obj1,0);把對象對象地址對應(yīng)的value清0

廢棄對象時(shí),會(huì)根據(jù)該對象的地址,找到weak表里面對應(yīng)的變量地址,然后給變量賦值nil。

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

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

  • 這幾天看了些關(guān)于內(nèi)存布局的文章,發(fā)帖總結(jié)摘錄下重點(diǎn)。 C語言的內(nèi)存模型 程序代碼區(qū)(code area) 存放函數(shù)...
    啟發(fā)禪悟閱讀 1,912評論 0 9
  • 序言:翻閱資料,學(xué)習(xí),探究,總結(jié),借鑒,謝謝探路者,我只是個(gè)搬運(yùn)工。參考、轉(zhuǎn)發(fā)資料:http://blog.csd...
    Init_ZSJ閱讀 1,437評論 0 0
  • 函數(shù)調(diào)用壓棧 https://zhuanlan.zhihu.com/p/27339191(操作系統(tǒng),或計(jì)算機(jī)體系結(jié)...
    憤怒小鳥飛呀飛閱讀 1,039評論 0 0
  • OC的底層實(shí)現(xiàn)是通過C/C++來實(shí)現(xiàn)的,所以內(nèi)存劃分和C比較相似OC內(nèi)存劃分為5個(gè)區(qū)代碼區(qū):代碼段是用來存放可執(zhí)行...
    hanyongwei閱讀 667評論 0 0
  • 3.1 OC特性之 內(nèi)存五大區(qū)域 此篇為針對Objective-c語言入門的基礎(chǔ)知識(shí),為了能讓大家更清楚的理解,此...
    阿新_會(huì)飛的猴子閱讀 1,875評論 3 10

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