在ios开发的世界里,通过动画来切换界面使我们早就习以为常的事情,但动画将一个原本同步执行的事务,变成一个异步事务,并由此引发了一系列的陷阱。
最近对公司产品的crashlytics报告进行了一些分析,发现这类bug在各个产品里都占据较高比例,因此总结了一下常见的case。

  1. present ViewController引发的混乱
    present一个controller的时候,如果一个present的动画正在执行过程当中,程序会抛出异常,异常告诉你Attempting to begin a modal transition from * to * while a transition is already in progress. Wait for viewDidAppear/viewDidDisappear to know the current transition has completed
    解决的办法是引入一个present事务控制器,用来对present请求进行排队,这种方案是否足够可靠,还有待验证。

  2. NavigationController引发的混乱
    与present类似,NavigationController的push&pop也会引发类似的错误,症状是,在多重push的时候不会立即crash,视图的内容部分会一团漆黑,但是在回退的时候会crash,异常是Fatal Exception: NSInvalidArgumentException Can't add self as subview,从crash的调用栈看,是navigationbar内部错误。
    解决的方法是可以继承UINavigationController,通过UINavigationControllerDelegate来监测状态,如果当前正在处于上一个push的执行过程当中,可以忽略掉新的push请求。

  3. UIScrollView(UITableView)的delegate引发的崩溃
    虽然ios5.0开始就已经支持weak引用,但很多的cocoa Touch类的delegate属性还是assign,这说明他们保存了一个不安全的引用。UIScrollView就是这样,如果controller里面有个UIScrollView,delegate属性是自身,那么有可能发生这样的情况:uiscrollview正在进行一个动画事务(出问题的case中,动画往往不是由于用户操作导致的),用户退出了当前的controller,动画完成的时候controller可能已经被dealloc,此时会发生EXEC_BAD_ACCESS崩溃。
    如果crash的的栈显示与UIScrollView有关,又表明是在Animation结束的时候,那么就很有可能是这个原因;这样的bug往往很难复现,据经验,一般出现在那些通过定时器启动动画的场合。
    因此,作为一种防御性的手段,建议在controller的dealloc里面,将相关的delegate置为nil

  4. 多个UI事件同时发生引发的混乱
    一个同事提供的线索,如果你同时点击UI页面的多个可点击控件,UI有可能发生混乱。
    比如同时点击多个button,uicontrol,绑定gesture的uiview等,只要刻意试一下我们的产品都有这个问题。
    现在的解决的方案是将相关可点击view的exclusiveTouch属性设置为true,如果工程里面UI控件都是用工厂方法创建的,那么改起来还是很方便的。
    不过gesture是不受这个属性的影响的,目前还没有发现如何解决,因此只能规避,如果能够使用UIControl来解决的问题,就不要使用UIView+Gesture来解决。
    这种问题如果不是刻意的去操作,一般还是很少会暴露的。

上面的几点是最近对线上一类疑难bug分析之后总结出来的根本原因;其本质上都是UI事务叠加导致的。上面1和2发生的根源一般都是,定时器或后台逻辑促发的界面切换,恰好和另一个界面切换撞在了一起,因此在测试的时候可能很难发现;在用户手上复现的概率也不是特别高,但总是会出现。所以在设计应用的时候,最好要避免这种从非用户操作导致的界面切换。

如果每个UI事务都不加动画、同步完成,那么就不会有这些情况,但这是不可能的。驱动App运行的所有事件源,包括定时任务、异步任务、用户操作、外部事件(比如推送消息)等,叠加在一起,使得完全避免上述的情况几乎不可能,关键是ios的UI框架对此基本不设防,只能靠我们自己积累经验,谨慎小心。

UI事务重叠引发的crash的更多相关文章

  1. [转]Spring事务嵌套引发的血案---Transaction rolled back because it has been marked as rollback-only

    原文地址:https://blog.csdn.net/f641385712/article/details/80445912 1.概述 想必大家一想到事务,就想到ACID,或者也会想到CAP.但笔者今 ...

  2. Spring事务嵌套引发的问题--Transaction rolled back because it has been marked as rollback-only

    转载https://blog.csdn.net/f641385712/article/details/80445912 读了两边才找到问题

  3. 用Fragment制作的Tab页面产生的UI重叠问题

    本文出处:http://blog.csdn.net/twilight041132/article/details/43812745 在用Fragment做Tab页面,发现有时候进入应用会同时显示多个T ...

  4. iOS:项目中疑难Crash问题集锦

    项目中疑难Crash问题集锦 iOS App运行中遇到Crash的情况相信大家都遇到过,开发和者测试中遇到了可能很方便的办法就是直接拿着设备连接一下,然后使用Xcode自带的工具就可以解析出Crash ...

  5. JNI NDK开发Crash错误定位 调试

    总结: 搜索backtrace  然后: $ /d/android-ndk-r10c/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86 ...

  6. Android NDK开发Crash错误定位[转]

    使用 ndk-stack 的时候需要你的 lib 编译为 debug版的,通常需要下面的修改: 1. 修改 android.mk,增加,为 LOCAL_CFLAGS 增加 -g 选项 2. 修改 ap ...

  7. 一些Windows API导致的Crash以及使用问题总结

    RegQueryValueEx gethostbyname/getaddrinfo _localtime64 FindFirstFile/FindNextFile VerQueryValue Crea ...

  8. Sqlserver事务隔离级别详解

    sqlserver存储方式   页    sqlserver是以页的形式存储数据,每个数据页的大小为8KB,sqlserver会把空间分为多个页,sqlserver与数据交互单位最小的io操作就是页级 ...

  9. sqlserver Distributed Transaction 分布式事务

    在webapi+ef+sqlserver开发项目时,利用transcope实现应用层级的事务时,偶尔会报分布式事务错误,而且很而复现,特别蛋疼.现将自己的解决方法初步整理下. 分析原因:搭建repos ...

随机推荐

  1. 一个2D平面游戏,的碰撞引擎实现

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); i ...

  2. js去重

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  3. bzoj2969 矩形粉刷

    学习一波用markdown写题解的姿势QAQ 题意 给你一个w*h的矩形网格,每次随机选择两个点,将以这两个点为顶点的矩形内部的所有小正方形染黑,问染了k次之后期望有多少个黑色格子. 分析 一开始看错 ...

  4. [BZOJ1607] [Usaco2008 Dec] Patting Heads 轻拍牛头 (数学)

    Description 今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏. 贝茜让N(1≤N≤100000)头奶牛坐成一个圈.除了1号与N号奶牛外,i号奶牛与i-l号和i+l号奶牛相邻.N号 ...

  5. 【Webpack的使用指南 01】Webpack入门

    使用Webpack有一段时间了,但是感觉之前学的用的都比较零散,所以在这里整理一下Webpack的使用知识,从入门到进阶. 创建项目 首先创建最简单的一个项目 npm init 得到以下项目结构: 安 ...

  6. MyBatis映射器元素

     映射器是MyBatis最强大的工具,也是我们使用MyBatis时用的最多的工具,映射器中主要有增删改查四大元素,来满足不同场景的需要: 下面是主要元素的介绍:         select:查询语句 ...

  7. eclipse 中启动Tomcat超时了错误

    修改E:\eclipse\eclipse\workspace\.metadata\.plugins\org.eclipse.wst.server.core\servers.xml 将 start-ti ...

  8. lambda表达式封装对数据库的查询

    前言: 1.为什么要封装lambda表达式数据库查询,原因有一下几点: 1.1.在以往的开发中进行数据库表查询时,其实所需要的字段就是其中几个,但是在开发中,开发者往往习惯select * 进行查询, ...

  9. k60引脚图

    /*! 枚举管脚编号 */ typedef enum { /* PTA端口 */ //0~31 PTA0, PTA1, PTA2, PTA3, PTA4, PTA5, PTA6, PTA7, PTA8 ...

  10. django Forbidden

    Forbidden (CSRF cookie not set.)解决方法 Forbidden (CSRF cookie not set.):xxx解决方法:在django项目的settings.py文 ...