iOS之迴圈引用問題

2021-08-21 23:40:17 字數 2943 閱讀 5027

記憶體中和變數有關的分割槽:堆、棧、靜態區。其中,棧和靜態區是作業系統自己管理的,對程式設計師來說相對透明,所以,一般我們只需要關注堆的記憶體分配,而迴圈引用的產生,也和其息息相關,即迴圈引用會導致堆裡的記憶體無法正常**,從而導致記憶體洩漏。

1、棧區(stack)— 由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。分配記憶體的時候,棧區的位址是 從上往下分配(越分配位址越小 i 位址比j大)

2、堆區(heap) — 一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由os** 。堆區的位址是 由下往上的

3、全域性區(靜態區)(static)— 全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域, 未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。 - 程式結束後有系統釋放

4、文字常量區— 常量字串就是放在這裡的。 程式結束後由系統釋放

5、程式**區— 存放函式體的二進位制**。

在ios中有2套記憶體管理機制:mrc(mannulreference counting)和arc(automatic reference counting)。其中arc起源於ios 4.3,在那之前,蘋果開發者只能手動使用retain和release來進行記憶體管理。這樣做的問題很明顯,如果你在開發過程中,乙個不小心沒有retain和release成對出現,那麼很容易使得記憶體沒有釋放,最後導致程式記憶體不足而導致閃退。

mrc

在你建立乙個物件的時候,他會需要進行retain,然後在你不在持有他的時候進行release,所以每個物件都有乙個retain count來進行計數。

記憶體管理規則如下:

1> 當呼叫alloc、new、copy(mutablecopy)方法產生乙個新物件的時候,就必須在最後呼叫一次release或者autorelease

2> 當呼叫retain方法讓物件的計數器+1,就必須在最後呼叫一次release或者autorelease

2.集合的記憶體管理細節

1> 當把乙個物件新增到集合中時,這個物件會做了一次retain操作,計數器會+1

2> 當乙個集合被銷毀時,會對集合裡面的所有物件做一次release操作,計數器會-1

3> 當乙個物件從集合中移除時,這個物件會一次release操作,計數器會-1

3.普遍規律

1> 如果方法名是add\insert開頭,那麼被新增的物件,計數器會+1

2> 如果方法名是remove\delete開頭,那麼被移除的物件,計數器-1

arc

ios 5.0之後引用自動管理機制——自動引用計數(arc),管理機制與手動機制一樣,只是不再需要呼叫retain、release、autorelease;它編譯時的特性,當你使用arc時,在適當位置插入release和autorelease;它引用strong和weak關鍵字,strong修飾的指標變數指向物件時,當指標指向新值或者指標不復存在,相關聯的物件就會自動釋放,而weak修飾的指標變數指向物件,當物件的擁有者指向新值或者不存在時weak修飾的指標會自動置為nil。

類相互引用

- (void)viewdidload
兩個類 a 和 b a強引用b b強引用a 所以下面的** dealloc 不會走 發生迴圈引用

解決方法 讓其中任意乙個類 變成弱引用即可 即 @property (nonatomic, weak) classa *classa;

執行結果如下:

2.block問題

- (void)blockfunc ;

self.block();

}

可以發現發生迴圈引用 解決辦法為 用weak 進行弱引用

- (void)blockfunc ;

self.block();

}

當在block中新增延遲函式時 下面函式就會出現問題

- (void)blockfunc );

};self.block();

}

1 列印null 5秒之內vc返回 此時vc 頁面消失 會走dealloc函式 故裡面的weakself會為空

2 列印hello 5秒之後vc返回 延遲函式已執行完 列印完整的hello vc 消失 走dealloc

解決辦法為 用strong 進行 強引用

- (void)blockfunc );

};self.block();

}

首先 weakself 就是弱引用 防止裡面迴圈引用 其次 內部的strongself是個 區域性變數 僅存在於棧中 當strongself.str 執行完 strongself就會** 不會造成迴圈引用 strongself 會使vc引用計數器加1 當其返回時 並不會立刻走dealloc函式 而是等strongself.str它執行完 引用計數為0 才會走dealloc 函式 所以不論什麼時候返回 strongself.str都是有值的 這就是為什麼__weak 和 __strong 成對出現的原因

3.nstimer

- (void)viewdidload 

- (void)timerclicked

這段**發生記憶體洩露 頁面消失 timerclicked函式一直執行

解決辦法為 didmovetoparentviewcontroller函式 將timer 置為空 或在合適位置將其timer取消

- (void)didmovetoparentviewcontroller:(uiviewcontroller *)parent 

}

iOS迴圈引用問題

今天面試問道了迴圈引用,所以就看了看,原來只是知道使用了block容易造成迴圈引用。今天就來簡單的介紹一些迴圈引用。先來簡單介紹一下什麼是迴圈引用?迴圈引用可以簡單的理解成 a物件引用了b物件,b物件又引用了a物件。兩者相互保持對方的乙個引用。導致任何時候計數都不為0,最終兩者都無法釋放。產生迴圈引...

iOS迴圈引用

class viewcontroller uiviewcontroller 迴圈引用的方法 func cycliclead completionback escaping void 當物件銷毀時會呼叫 deinit oc方式 weak typeof self weakself self self.b...

iOS開發中的迴圈引用問題

nstimer經常會被作為類的成員變數,而nstimer初始化時要指定self為target,造成迴圈引用。另一方面,若timer一直處於validate的狀態,則其引用計數將始終大於0。先看一段nstimer使用的例子 arc模式 解決方案 自定義類 wsweaktimertarget h檔案 i...