隨便說說removeFromSuperview方法

2021-07-22 14:52:21 字數 4502 閱讀 7175

專欄作者。

之前寫過一篇關於removefromsuperview方法處理的文章,寫完後一直就沒怎麼更新這篇文章。這兩天回過頭來看看,感覺這篇文章有些地方寫的不夠嚴謹,而且還有一些自己理解錯的地方,所以打算重寫這篇文章。

在使用removefromsuperview方法的時候,發現這個方法有很多我們沒有注意的地方。而且對於一些不規範的操作,蘋果也對其進行了容錯處理。所以我對removefromsuperview的一些使用細節整理了一下,

包括arc和mrc兩種情況

佔位圖

測試環境

執行環境

版本號xcode

7.1mac os x

10.11

ios9.3.1

硬體裝置

iphone 5s

檢視結構

ios應用中,檢視的結構是樹型資料結構,以這種結構來控制檢視顯示,這種資料結構有乙個很好的優點:

層級關係分明,並且方便傳遞事件。從根節點出發,通過葉節點向下擴充套件,同一枝的上乙個節點就是下乙個節點的superview,下乙個節點就是上乙個節點的subview。每個應用程式都有乙個主window,這個window就是根節點。

removefromsuperview

每乙個view都和檢視結構以及響應者鏈有直接的關係,但是這篇文章不打算著重的講這兩個方面,主要講removefromsuperview方法。將當前檢視從其父檢視移除,需要呼叫removefromsuperview方法。下面是蘋果對於這個api的官方定義:

unlinks the receiver from its superview and its window, and removes it from the responder chain.
譯:把當前view從它的父view和視窗中移除,同時也把它從響應事件操作的響應者鏈中移除。

removefromsuperview就是乙個檢視節點刪除的操作,執行這個方法,就等於在樹形結構中找到該節點,從樹型資料結構中刪除該節點及其子節點,而並非只是刪除該節點自己。同時,另乙個操作就是把該物件從響應者鏈中移除。

執行removefromsuperview方法後,會從父檢視中移除,並且將superview對檢視的強引用刪除,此時如果沒有其他地方再對檢視進行強引用,則會從記憶體中移除。如果還存在其他強引用,檢視只是不在螢幕中顯示,並沒有將該檢視從記憶體中移除。所以如果需要使用該檢視,不需要再次建立,而是直接addsubview就可以了。

對於這個api,蘋果並沒有給出過多的解釋,只是簡單的描述了一下這個api,以及說明了這個api的注意點。所以,下面將會根據我的使用經驗,繼續講解這個api。

記憶體管理

方法呼叫後的記憶體管理

經過測試,在arc的情況下執行removefromsuperview方法多次也沒有問題,因為arc記憶體是系統為我們管理的。

但是在mrc中,根據官方api的說明:

if the view』s superview is

not nil, the superview releases the view.

也就是每執行一次removefromsuperview方法,方法內部都會執行一次release操作。但是經過我的測試,發現呼叫removefromsuperview方法後,引用計數並沒有減少,反而增加了乙個。(我是通過呼叫retaincount檢視的引用計數,但是並不是真正準確的,後面會講解這個問題)

記憶體陷阱

那如果是這樣,那就遇到乙個和我們之前認知不太相同的答案了。具體是什麼問題,還是需要自己寫**驗證,於是我基於上面描述的測試環境,寫了一些關於檢視的測試**。

uiview *view = [[uiview alloc] initwithframe:[uiscreen mainscreen].bounds];

[self

.view addsubview:view];

[view release];

[view removefromsuperview];

// 多次呼叫remove方法

[view removefromsuperview];

經過我的測試發現,呼叫removefromsuperview方法後引用計數並沒有增加,呼叫完之後還是會release的。我們之前看到的引用計數的增加,是因為系統的隱藏操作導致的。之前在mrc時期經常發現retaincount不準確,這主要是因為ios系統api的引用、或自動釋放池導致的,所以retaincount並不能當做可靠的參考。

所以,如果呼叫多個release,還是會崩潰的,始終要相信iosmrc記憶體管理原則,這才是可靠的。可以多次呼叫removefromsuperview方法,在已經移除父檢視後,其他多餘的呼叫不會改變任何引用計數。對於addsubview:方法也是一樣的,下面會講這個方法。

使用細節

多次執行addsubview:操作

假設現在有viewaviewbviewc三個檢視,viewa新增到viewb之後又要新增到viewc上面,此時viewa同時執行了向viewbviewc兩個檢視addsubview:的操作。但是因為只有乙個檢視物件,所以只會以最後一次新增的為準,第一次執行的新增到viewb的操作是無效的。通過列印兩個view的子檢視可以看到,只有最後執行的新增到viewc上的操作才是有效的,viewc才真正擁有了viewa,而viewb的子檢視是空的。

乙個檢視不只是向其他多個頁面進行新增操作不會出現問題,而且向同乙個檢視上執行多次新增操作也是沒有問題的,並不會導致檢視被多次新增的問題,也不需要在新增之前進行removefromsuperview操作,這個是在mrcarc都是有效的。因為系統在addsubview:方法中進行了一些判斷操作,如果當前檢視已經新增到其他檢視,會將當前檢視從其他檢視中移除,然後執行新增操作。如果當前檢視已經新增到這個檢視中,就不會再次執行新增操作。

乙個小坑

其實也說不上是坑,可以算是乙個了解的知識點吧。在arcmrc的情況下,呼叫removefromsuperviewaddsubview:方法其中之一,都需要在另乙個方法已經執行的情況下才會有效,對於多次執行乙個同方法系統也是有判斷操作的,並不會被執行多次。

例如呼叫remove方法之後,此時檢視已經不在父檢視之上了,在多次呼叫這個方法是不起作用的,而且mrc下引用計數也不會被減少多次。對於addsubview:方法也是一樣的,向同乙個父檢視上新增子檢視,不會被重複新增,新增之後引用計數也不會多次+1

注意點無論是arc還是mrc中多次呼叫removefromsuperviewaddsubview:方法,都不會造成造成重複釋放和新增。

蘋果的官方api註明:never call this method from inside your view』s drawrect: method.

譯:永遠不要在你的viewdrawrect:方法中呼叫removefromsuperview

我來隨便說說

好久沒來兄弟連bbs了,隨便說說 正文 來兄弟連大約有895小時了,感觸也挺多.來之前 時不時地上網玩遊戲,而且生活也很不規律,根本都不敢想象以後會怎樣.可能買苦力.其實 我玩過之後有一種 罪惡感.一覺睡到12點也是常有的,感覺大學學不到什麼東西,一直想找個環境來鍛鍊自己,現在我想我找到了.起初來的...

隨便說說的題

題目描述 兔子,兔子,和很多新的兔子。乙隻兔子每天會生下 k kk 只兔子。生下來的小兔子,從第二天開始就會變成大兔子,並且生產。舉例,k 1 k 1k 1 時,兔子數量在前三天分別是 1 11 只兔子 1 11 隻大兔 1 11 只小兔 2 22 隻大兔 2 22 只小兔。現在蘇蘇正在研究這群兔子...

專案上線之隨便說說

公司實施的siebel系統上線準備階段,加班加到一塌糊塗.基本每天都在10點半才離開公司,打車回家.畢業六七年,這還是頭一回.不過,也是難得的經歷,尤其對我這種在甲方做系統維護的人來說,專案實施經驗是珍貴的經歷.角色是siebel系統與sap系統的整合 學徒,跟著顧問混.也算是稍有心得.專案結束後好...