專欄作者。
之前寫過一篇關於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
,還是會崩潰的,始終要相信ios的mrc記憶體管理原則,這才是可靠的。可以多次呼叫removefromsuperview
方法,在已經移除父檢視後,其他多餘的呼叫不會改變任何引用計數。對於addsubview:
方法也是一樣的,下面會講這個方法。使用細節
多次執行addsubview:操作
假設現在有
viewa
、viewb
、viewc
三個檢視,viewa
新增到viewb
之後又要新增到viewc
上面,此時viewa
同時執行了向viewb
、viewc
兩個檢視addsubview:
的操作。但是因為只有乙個檢視物件,所以只會以最後一次新增的為準,第一次執行的新增到viewb
的操作是無效的。通過列印兩個view
的子檢視可以看到,只有最後執行的新增到viewc
上的操作才是有效的,viewc
才真正擁有了viewa
,而viewb
的子檢視是空的。乙個檢視不只是向其他多個頁面進行新增操作不會出現問題,而且向同乙個檢視上執行多次新增操作也是沒有問題的,並不會導致檢視被多次新增的問題,也不需要在新增之前進行
removefromsuperview
操作,這個是在mrc和arc都是有效的。因為系統在addsubview:
方法中進行了一些判斷操作,如果當前檢視已經新增到其他檢視,會將當前檢視從其他檢視中移除,然後執行新增操作。如果當前檢視已經新增到這個檢視中,就不會再次執行新增操作。乙個小坑
其實也說不上是坑,可以算是乙個了解的知識點吧。在arc或mrc的情況下,呼叫
removefromsuperview
和addsubview:
方法其中之一,都需要在另乙個方法已經執行的情況下才會有效,對於多次執行乙個同方法系統也是有判斷操作的,並不會被執行多次。例如呼叫remove方法之後,此時檢視已經不在父檢視之上了,在多次呼叫這個方法是不起作用的,而且mrc下引用計數也不會被減少多次。對於
addsubview:
方法也是一樣的,向同乙個父檢視上新增子檢視,不會被重複新增,新增之後引用計數也不會多次+1。注意點無論是arc還是mrc中多次呼叫
removefromsuperview
和addsubview:
方法,都不會造成造成重複釋放和新增。蘋果的官方api註明:
never call this method from inside your view』s drawrect: method.
譯:永遠不要在你的
view
的drawrect:
方法中呼叫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系統的整合 學徒,跟著顧問混.也算是稍有心得.專案結束後好...