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了。

  • 相关阅读:
    Enterprise Library 企业库 V4.1
    跨域实现IFRAME自适应高度
    微软企业库4.1学习笔记(二)各功能之间的依赖关系以及对象创建
    微软企业库4.1学习笔记(三)企业库迁移和并行使用,以及企业库的扩展
    微软企业库4.1学习笔记(五)对象创建和依赖注入方法
    判断 iframe 是否加载完成的完美方法
    对JavaScript调用堆栈和setTimeout用法的深入研究
    工作流技术杂谈
    企业流程管理平台V2.0介绍(.NET平台下的工作流)
    c#操作oracle lob字段[转自 芽芽的回收站]
  • 原文地址:https://www.cnblogs.com/pigpigDD/p/3917987.html
Copyright © 2011-2022 走看看