【iOS開發每日小筆記(四)】iOS 7中如何除去UIAlertView 規避delegate對象銷毀後接收訊息的crash

來源:互聯網
上載者:User

標籤:style   blog   http   color   os   io   strong   資料   

這篇文章是我的【iOS開發每日小筆記】系列中的一片,記錄的是今天在開發工作中遇到的,可以用很短的文章或很小的demo示範解釋出來的小心得小技巧。該分類的文章,內容涉及的知識點可能是很簡單的、或是用很短程式碼片段就能實現的,但在我看來它們可能會給使用者體驗、代碼效率得到一些提升,或是之前自己沒有接觸過的技術,很開心的學到了,放在這裡得瑟一下。其實,90%的作用是協助自己回顧、記憶、複習。如果看官覺得太easy,太片段,則可以有兩個選擇:1,移步【iOS探究】分類,對那裡的文章進行斧正;2,在本文的評論裡狠狠吐槽,再關掉頁面!感謝!

 

測試組的同學想盡辦法測我們的bug,盡心儘力。今天他們發現,在某些時候UIAlertView彈出後,不關閉UIAlertView直接點擊home鍵退到iOS主介面,再次進入程式,點擊剛剛的UIAlertView上的按鈕,程式crash。根據我的經驗,一看便知肯定是訊息傳給了被釋放的對象,造成的crash

首先來解釋一下背景,目前我所做的項目,是一個幾十人同時線上的教育類項目,介面層次關係也比較冗雜。先且不談設計是否合理,為了同步重新整理狀態等原因,我們在程式退出到後台時,會刪除當前的若干介面,程式再次進入時,會從伺服器擷取當前資料和狀態,再據此重新建立若干介面。而UIAlertView本身是不會因為你退出到後台後再進入而自動消失(dismiss)的。因此問題就來了,假如我的UIAlertView的回調對象(delegate)設定的是某個將要銷毀的View,那麼點擊home鍵程式退到後台,這個View被銷毀,delegate指向的記憶體地區就是被釋放的地區,再進入程式,點擊UIAlertView上的按鈕,發送訊息就必然crash。(可以參考我的demo:在這裡https://github.com/pigpigdaddy/ClearAlertViewDemo)

 

 1 #import "MySubView.h" 2  3 @implementation MySubView 4  5 - (id)initWithFrame:(CGRect)frame 6 { 7     self = [super initWithFrame:frame]; 8     if (self) { 9         // Initialization code10         11         self.backgroundColor = [UIColor darkGrayColor];12         13         UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"testAlert" message:@"TEST" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];14         [alertView show];15     }16     return self;17 }18 19 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex20 {21     22 }23 24 @end

 

可以看到在我的自訂View中,建立了一個UIAlertView,他的代理指向了self。

而在AppDelegate中,我在每次退到後台時,將自訂View給刪除了:

1 - (void)applicationWillResignActive:(UIApplication *)application2 {3     ViewController *rootViewController = (ViewController *)self.window.rootViewController;4     [rootViewController removeSubView];5 }

重新進來後,點擊確定crash,這樣就類比了這個crash。

 

於是想到解決方案,1,程式退出到後台時設定delegate為nil,(請注意,OC中,向nil發送訊息,是可以的。不會crash,也什麼都不會發生);2,程式退到後台時,手動dismiss當前的UIAlertView。

嘗試了第二條,因為第二條更合理,設為nil的確可以規避掉crash,但是你的點擊只能將UIAlertView給dismiss掉,而點擊選擇的功能將失效。

我們知道iOS 7之前,可以通過UIApplication 的 windows擷取到UIAlertView所在的window,然後消除UIAlertView(具體可看這篇文章:http://blog.csdn.net/u010889390/article/details/18499691 不過很抱歉此刻我手邊沒有iOS 6 的 SDK不能去再次驗證,但是我的確在iOS5或iOS6這麼做過)。但是iOS 7開始,你無法擷取到這個windows了,因為UIAlertView展現方式做出了變化,簡而言之就是你不能通過UIApplication拿到UIAlertView了。你唯一能做的就是在建立的地方儲存一份UIAlertView執行個體的引用,然後在適合的地方再去做其他動作(如本例中的銷毀View時,手動dismiss掉UIAlertView)。

回到程式中,將我們的自訂View的做這樣的改變:

1 #import <UIKit/UIKit.h>2 3 @interface MySubView : UIView<UIAlertViewDelegate>4 5 @property (nonatomic, strong)UIAlertView *alertView;6 7 @end
 1 #import "MySubView.h" 2  3 @implementation MySubView 4  5 - (id)initWithFrame:(CGRect)frame 6 { 7     self = [super initWithFrame:frame]; 8     if (self) { 9         // Initialization code10         11         self.backgroundColor = [UIColor darkGrayColor];12         13 //        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"testAlert" message:@"TEST" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];14 //        [alertView show];15         16         self.alertView = [[UIAlertView alloc] initWithTitle:@"testAlert" message:@"TEST" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];17         [self.alertView show];18     }19     return self;20 }21 22 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex23 {24     25 }26 27 @end

然後重新定義ViewController中的removeSubView方法:

1 - (void)removeSubView2 {3     MySubView *view = (MySubView *)[self.view viewWithTag:1000];4     if (view) {5         [view.alertView dismissWithClickedButtonIndex:0 animated:YES];6         [view removeFromSuperview];7     }8 }

運行後,退出到後台,再進入,此時的UIAlertView已經dismiss。不會再有使用者因為點擊了殘留的UIAlertView而Crash了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.