隨便說說removeFromSuperview方法

該文章屬于劉小壯原創(chuàng),轉(zhuǎn)載請(qǐng)注明:劉小壯


配圖

之前寫過一篇關(guān)于removeFromSuperview方法處理的文章,寫完后一直就沒怎么更新這篇文章。這兩天回過頭來看看,感覺這篇文章有些地方寫的不夠嚴(yán)謹(jǐn),而且還有一些自己理解錯(cuò)的地方,所以打算重寫這篇文章。

在使用removeFromSuperview方法的時(shí)候,發(fā)現(xiàn)這個(gè)方法有很多我們沒有注意的地方。而且對(duì)于一些不規(guī)范的操作,蘋果也對(duì)其進(jìn)行了容錯(cuò)處理。所以我對(duì)removeFromSuperview的一些使用細(xì)節(jié)整理了一下,包括ARCMRC兩種情況。其中還會(huì)簡(jiǎn)單涉及一些內(nèi)存管理相關(guān)的部分,文章中有什么問題,還希望多多指出,謝謝!??


測(cè)試環(huán)境

運(yùn)行環(huán)境 版本號(hào)
Xcode 7.1
Mac OS X 10.11
iOS 9.3.1
硬件設(shè)備 iPhone 5S

視圖結(jié)構(gòu)

iOS應(yīng)用中,視圖的結(jié)構(gòu)是樹型數(shù)據(jù)結(jié)構(gòu),以這種結(jié)構(gòu)來控制視圖顯示,這種數(shù)據(jù)結(jié)構(gòu)有一個(gè)很好的優(yōu)點(diǎn):
層級(jí)關(guān)系分明,并且方便傳遞事件。從根節(jié)點(diǎn)出發(fā),通過葉節(jié)點(diǎn)向下擴(kuò)展,同一枝的上一個(gè)節(jié)點(diǎn)就是下一個(gè)節(jié)點(diǎn)的superview,下一個(gè)節(jié)點(diǎn)就是上一個(gè)節(jié)點(diǎn)的subview。每個(gè)應(yīng)用程序都有一個(gè)主window,這個(gè)window就是根節(jié)點(diǎn)。

removeFromSuperview

每一個(gè)View都和視圖結(jié)構(gòu)以及響應(yīng)者鏈有直接的關(guān)系,但是這篇文章不打算著重的講這兩個(gè)方面,主要講removeFromSuperview方法。將當(dāng)前視圖從其父視圖移除,需要調(diào)用removeFromSuperview方法。下面是蘋果對(duì)于這個(gè)API的官方定義:

Unlinks the receiver from its superview and its window, and removes it from the responder chain.

譯:把當(dāng)前View從它的父View和窗口中移除,同時(shí)也把它從響應(yīng)事件操作的響應(yīng)者鏈中移除。

removeFromSuperview就是一個(gè)視圖節(jié)點(diǎn)刪除的操作,執(zhí)行這個(gè)方法,就等于在樹形結(jié)構(gòu)中找到該節(jié)點(diǎn),從樹型數(shù)據(jù)結(jié)構(gòu)中刪除該節(jié)點(diǎn)及其子節(jié)點(diǎn),而并非只是刪除該節(jié)點(diǎn)自己。同時(shí),另一個(gè)操作就是把該對(duì)象從響應(yīng)者鏈中移除。

執(zhí)行removeFromSuperview方法后,會(huì)從父視圖中移除,并且將Superview對(duì)視圖的強(qiáng)引用刪除,此時(shí)如果沒有其他地方再對(duì)視圖進(jìn)行強(qiáng)引用,則會(huì)從內(nèi)存中移除。如果還存在其他強(qiáng)引用,視圖只是不在屏幕中顯示,并沒有將該視圖從內(nèi)存中移除。所以如果需要使用該視圖,不需要再次創(chuàng)建,而是直接addSubview就可以了。

對(duì)于這個(gè)API,蘋果并沒有給出過多的解釋,只是簡(jiǎn)單的描述了一下這個(gè)API,以及說明了這個(gè)API的注意點(diǎn)。所以,下面將會(huì)根據(jù)我的使用經(jīng)驗(yàn),繼續(xù)講解這個(gè)API。

內(nèi)存管理

方法調(diào)用后的內(nèi)存管理

經(jīng)過測(cè)試,在ARC的情況下執(zhí)行removeFromSuperview方法多次也沒有問題,因?yàn)?strong>ARC內(nèi)存是系統(tǒng)為我們管理的。

但是在MRC中,根據(jù)官方API的說明:
If the view’s superview is not nil, the superview releases the view.

也就是每執(zhí)行一次removeFromSuperview方法,方法內(nèi)部都會(huì)執(zhí)行一次release操作。但是經(jīng)過我的測(cè)試,發(fā)現(xiàn)調(diào)用removeFromSuperview方法后,引用計(jì)數(shù)并沒有減少,反而增加了一個(gè)。(我是通過調(diào)用retainCount查看的引用計(jì)數(shù),但是并不是真正準(zhǔn)確的,后面會(huì)講解這個(gè)問題)

內(nèi)存陷阱

那如果是這樣,那就遇到一個(gè)和我們之前認(rèn)知不太相同的答案了。具體是什么問題,還是需要自己寫代碼驗(yàn)證,于是我基于上面描述的測(cè)試環(huán)境,寫了一些關(guān)于視圖的測(cè)試代碼。

UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.view addSubview:view];
[view release];
[view removeFromSuperview];
// 多次調(diào)用remove方法
[view removeFromSuperview];

經(jīng)過我的測(cè)試發(fā)現(xiàn),調(diào)用removeFromSuperview方法后引用計(jì)數(shù)并沒有增加,調(diào)用完之后還是會(huì)release的。我們之前看到的引用計(jì)數(shù)的增加,是因?yàn)橄到y(tǒng)的隱藏操作導(dǎo)致的。之前在MRC時(shí)期經(jīng)常發(fā)現(xiàn)retainCount不準(zhǔn)確,這主要是因?yàn)?strong>iOS系統(tǒng)API的引用、或自動(dòng)釋放池導(dǎo)致的,所以retainCount并不能當(dāng)做可靠的參考。

所以,如果調(diào)用多個(gè)release,還是會(huì)崩潰的,始終要相信iOSMRC內(nèi)存管理原則,這才是可靠的??梢远啻握{(diào)用removeFromSuperview方法,在已經(jīng)移除父視圖后,其他多余的調(diào)用不會(huì)改變?nèi)魏我糜?jì)數(shù)。對(duì)于addSubview:方法也是一樣的,下面會(huì)講這個(gè)方法。

使用細(xì)節(jié)

多次執(zhí)行addSubview:操作

假設(shè)現(xiàn)在有ViewAViewB、ViewC三個(gè)視圖,ViewA添加到ViewB之后又要添加到ViewC上面,此時(shí)ViewA同時(shí)執(zhí)行了向ViewB、ViewC兩個(gè)視圖addSubview:的操作。但是因?yàn)橹挥幸粋€(gè)視圖對(duì)象,所以只會(huì)以最后一次添加的為準(zhǔn),第一次執(zhí)行的添加到ViewB的操作是無效的。通過打印兩個(gè)View的子視圖可以看到,只有最后執(zhí)行的添加到ViewC上的操作才是有效的,ViewC才真正擁有了ViewA,而ViewB的子視圖是空的。

一個(gè)視圖不只是向其他多個(gè)頁面進(jìn)行添加操作不會(huì)出現(xiàn)問題,而且向同一個(gè)視圖上執(zhí)行多次添加操作也是沒有問題的,并不會(huì)導(dǎo)致視圖被多次添加的問題,也不需要在添加之前進(jìn)行removeFromSuperview操作,這個(gè)是在MRCARC都是有效的。因?yàn)橄到y(tǒng)在addSubview:方法中進(jìn)行了一些判斷操作,如果當(dāng)前視圖已經(jīng)添加到其他視圖,會(huì)將當(dāng)前視圖從其他視圖中移除,然后執(zhí)行添加操作。如果當(dāng)前視圖已經(jīng)添加到這個(gè)視圖中,就不會(huì)再次執(zhí)行添加操作。

一個(gè)小坑

其實(shí)也說不上是坑,可以算是一個(gè)了解的知識(shí)點(diǎn)吧。在ARCMRC的情況下,調(diào)用removeFromSuperviewaddSubview:方法其中之一,都需要在另一個(gè)方法已經(jīng)執(zhí)行的情況下才會(huì)有效,對(duì)于多次執(zhí)行一個(gè)同方法系統(tǒng)也是有判斷操作的,并不會(huì)被執(zhí)行多次。

例如調(diào)用remove方法之后,此時(shí)視圖已經(jīng)不在父視圖之上了,在多次調(diào)用這個(gè)方法是不起作用的,而且MRC下引用計(jì)數(shù)也不會(huì)被減少多次。對(duì)于addSubview:方法也是一樣的,向同一個(gè)父視圖上添加子視圖,不會(huì)被重復(fù)添加,添加之后引用計(jì)數(shù)也不會(huì)多次+1。

注意點(diǎn)

  1. 無論是ARC還是MRC中多次調(diào)用removeFromSuperviewaddSubview:方法,都不會(huì)造成造成重復(fù)釋放和添加。
  2. 蘋果的官方API注明:Never call this method from inside your view’s drawRect: method.
    譯:永遠(yuǎn)不要在你的ViewdrawRect:方法中調(diào)用removeFromSuperview。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Core Animation基礎(chǔ) Core Animation 利用了硬件加速和架構(gòu)上的優(yōu)化來實(shí)現(xiàn)快速渲染和實(shí)時(shí)動(dòng)...
    獨(dú)木舟的木閱讀 1,695評(píng)論 0 3
  • 翻譯自“Collection View Programming Guide for iOS” 0 關(guān)于iOS集合視...
    lakerszhy閱讀 4,066評(píng)論 1 22
  • addSubview: 添加一個(gè)子視圖到接收者并讓它在最上面顯示出來。 - (void)addSubview:(U...
    默默_David閱讀 3,208評(píng)論 0 1
  • 概述 視圖是應(yīng)用程序中用戶界面的基本組成部分,UIView類定義了所有視圖的通用行為。視圖在其邊界矩形內(nèi)呈現(xiàn)內(nèi)容,...
    漸z閱讀 1,594評(píng)論 0 0

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