在了解控制器的生命周期之后,我們都知道viewWillAppear:方法是在控制器的view將要顯示的時候調用的,而viewWillDisappear:方法是在控制器的view將要隱藏的時候調用。很多時候我們根據自身需要將相關代碼邏輯添加到這兩個方法中,我們看下如下代碼片段:
這段代碼是在控制器的viewDidLoad:方法中注冊了一個鍵盤彈出的通知和鍵盤隱藏的通知,然后在調用到相關方法時分別在控制臺打印,在viewWillDisappear:界面即將隱藏的時候移除通知,具體效果如下圖:
這看上去沒什么問題,鍵盤的顯示和隱藏也都能監聽到。尼瑪!被騙了???
其實并不然,細心的開發人員會知道,蘋果在iOS7中增加了導航控制器側滑返回功能,現在絕大多數App都使用了這項功能(有些App重寫了自帶的返回鍵之后忘記開啟左滑返回手勢了)。那么這項功能會帶來什么問題呢?我們接著看下面的操作:
隨著iphone手機屏幕越來越大,左上角的返回按鈕早已夠不到(原諒我手小= =!),很多“手賤”的人喜歡通過這種側滑的形式返回上一個界面(其實說的是我。。。),而這種側滑返回會出現什么問題呢?當觸發側滑返回時會調用系統自帶的viewWillDisappear:方法,在該方法中將監聽鍵盤顯示和隱藏的通知移除后,要是這時候用戶取消了側滑返回(即回到了原始狀態),那么再點擊界面上的textField喚出鍵盤,是不會發送鍵盤顯示和隱藏的通知了,因為通知已被移除。。。
那么遇到這種情況有什么方法解決么?
我這里提供兩種解決方案:
1、將注冊監聽鍵盤顯示和隱藏的代碼放到viewWillAppear:方法中
因為在觸發側滑返回后又取消側滑,則會調用viewWillAppear:方法。那么如果側滑返回將通知移除,則在取消側滑時又會將通知重新添加進去。
2、將移除通知的代碼放到dealloc方法中
dealloc方法是在控制器銷毀之時調用的。這個時候移除通知而不是在viewWillDisappear:方法中移除可以有效避免上述的問題。既然控制器都銷毀了,那么還留著相關的通知干嘛?該移除的移除。
上面給出了兩種解決方案,要說哪種最優,還得視情況而定。
我在這里可以舉個??。假如我們現在有這么個場景:在控制器的view上有個label,在label上添加一個手勢(一般手勢都是在創建完label之后添加的),假設我在viewWillDisappear:方法中移除該手勢,則此時用戶側滑返回之時又取消側滑返回,那么原先在label上的手勢卻再也添加不回來了(這里label一般在viewDidLoad方法中創建),因為viewDidLoad方法不會再次調用。而第二種方法卻可以有效避免這種情況,這樣就可以避免我這種“手賤”的任意搗鼓了。
而第一種方案比較適合在這種情境下使用:當A控制器的view中有個文本輸入框,需要監聽鍵盤的顯示和隱藏事件,當該頁面push到B控制器時,若B控制器恰巧也需要監聽鍵盤顯示和隱藏事件,這時候若不將A控制器的監聽事件給移除的話,那么B控制器中鍵盤顯示或隱藏時,A控制器中也會接收到通知并作出相應的事件處理,而這有可能是我們不期望出現的,所以該情況下在viewWillAppear:方法中添加通知,在viewWillDisappear:方法中移除通知比較合適。
最后,我們再來總結下重點:
1、iOS7新增加了導航控制器側滑手勢,當觸發側滑返回時,會調用系統的viewWillDisappear:方法,取消側滑返回時又會調用viewWillAppear:方法。
2、在做手勢和通知等一系列操作之時要分情況考慮:若通知和手勢是與UI相關的,如監聽UITextField鍵盤的顯示和隱藏通知等應該在viewWillAppear:方法中添加通知,在viewWillDisappear:方法中移除通知;而與UI無關的通知和手勢,像自定義通知等,應該在viewDidLoad等一次性方法中添加,在dealloc方法中釋放。在此感謝@xiubin 和 @KtZhang給以的指正。
3、在viewWillAppear:、viewWillDisappear:、viewDidAppear:、viewDidDisappear:等類似于這種會多次調用的系統方法中添加代碼時,一定要多考慮業務邏輯,以免出現不必要的麻煩。
轉自:http://www.jianshu.com/p/ea2aadef413d注冊、取消通知的代碼放在哪里,應該取決于這個通知的性質。如果是和視圖相關的,比如鍵盤、UI事件等,就選viewWillAppear/viewWillDisappear這一組。否則你有可能好幾個VC同時觸發通知的回調函數。如果是和VC相關的,比如和網絡、異步IO等相關的通知,就用viewDidLoad和dealloc這一組。
新聞熱點
疑難解答