zoukankan      html  css  js  c++  java
  • 【iOS开发每日小笔记(四)】iOS 7中如何除去UIAlertView 规避delegate对象销毁后接收消息的crash

    这篇文章是我的【iOS开发每日小笔记】系列中的一片,记录的是今天在开发工作中遇到的,可以用很短的文章或很小的demo演示解释出来的小心得小技巧。它们可能会给用户体验、代码效率得到一些提升,或是之前自己没有接触过的技术,很开心的学到了,放在这里得瑟一下。90%的作用是帮助自己回顾、记忆、复习。

    测试组的同学想尽办法测我们的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 code
    10         
    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)buttonIndex
    20 {
    21     
    22 }
    23 
    24 @end

    可以看到在我的自定义View中,创建了一个UIAlertView,他的代理指向了self。

    而在AppDelegate中,我在每次退到后台时,将自定义View给删除了:

    1 - (void)applicationWillResignActive:(UIApplication *)application
    2 {
    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 code
    10         
    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)buttonIndex
    23 {
    24     
    25 }
    26 
    27 @end

    然后重新定义ViewController中的removeSubView方法:

    1 - (void)removeSubView
    2 {
    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了。

  • 相关阅读:
    【leetcode】1295. Find Numbers with Even Number of Digits
    【leetcode】427. Construct Quad Tree
    【leetcode】1240. Tiling a Rectangle with the Fewest Squares
    【leetcode】1292. Maximum Side Length of a Square with Sum Less than or Equal to Threshold
    【leetcode】1291. Sequential Digits
    【leetcode】1290. Convert Binary Number in a Linked List to Integer
    【leetcode】1269. Number of Ways to Stay in the Same Place After Some Steps
    【leetcode】1289. Minimum Falling Path Sum II
    【leetcode】1288. Remove Covered Intervals
    【leetcode】1287. Element Appearing More Than 25% In Sorted Array
  • 原文地址:https://www.cnblogs.com/pigpigDD/p/3917987.html
Copyright © 2011-2022 走看看