浅谈iOS调试技巧的实际应用(二) UI篇

前篇简单介绍了断点及几个调试命令的使用的使用。

   做iOS开发, 大部分的工作跟UI相关,而分析UI最重要的就是分析UI的Hierarchy,这篇就是围绕View Hierarchy来详细介绍UI相关的调试技巧

  • 获取Hierarchy

巧妇难为无米之炊,首先我们得得到Hierarchy,方法是调用某个UIView对象或其子类的recursiveDescription方法

recursiveDescription方法是UIView的私有方法。苹果未公开该方法。常用的的场合是, 在任意断点处执行

po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]
或
po [oneView recursiveDescription]

该方法将递归打印该View的所有子View的层次关系,效果如下图:

  • 通过Hierarchy能解决哪些问题? 可用在哪些场景?
    • 场景1: 获取当前正在显示的是哪个页面(ViewController)?

   好吧, 同事在很专心的思索某个问题, 我不忍心打扰他,我想知道他的VC是什么, 做了什么事情?或者想知道某个问题它是如何处理的。

   这时, 你先在模拟器里定位到他的页面, 然后pause program,再在控制台打印当前keyWindow的Hierarchy,然后从输出信息里, 从按照等级从高到低(将View前的“|”的数量定义为该View的等级,越少等级越高), 然后同一等级下从下往上找。因为,在打印信息里,在同一层级下,越往下的View,zOrder越高。zOrder高的View当然会盖住zOrder低的View。

    以上图为例, 你发现<UIView: 0x8d75ba0...你要找的View。因为前面的都是系统的View。它会将你包裹起来做其他事情。

   好了,View知道了, 那VC呢?

    对象与对象之间的关系在某种程度上可以分为3种:1.互不相知, 2.单向引用, 3,双向引用。后面2种有点像链表。我们都知道通过VC的view属性就可以找到View了。但是,好像从来没有过通过view找到它的VC的经验?对吧。但是,也许, 你会猜,View应该也会记住它的VC是谁吧。是的。 事实确实如此。

如图(UIView的.h文件), 你发现你找到证据了,VC是view的一个代理,对的, 因为View有时候需要让VC去做一些事情。 但是,这只是结构体中的一个变量了。它不是一个类的属性, 没有get, set方法, 你不能通过给对象发送消息来获取这个值啊。因为没有这个方法。 那怎么办呢? 对了。 这时OC Runtime的KVO机制就可以发挥作用了。

[oneView ValueForKey:@"_viewDelegate"]

上面这个方法就可以获取view的VC是谁了。

除了上面KVO的方法?还有其他方法吗?答案是:有的。

如果你了解UI的事件传递机制。你会知道消息会一直从hitTestView一直往上forward, 直到UIApplication为止。这个工作是由基类UIResponder完成的。当一个Responder对象不对事件处理时, 它会调用nextResponder方法找到Responder Chain的下一个对象, 然后丢给它处理。

好了。如果一个View有它的VC, 按照事件传递机制, 它的nextResponder必定是VC。对了,如此问题就解决了。 调用View的nextResponder就一定能找到它的VC是谁。是不是很简单呢?

[oneView nextResponder]
场景2: 为什么我的视图没显示呢?或者在某个时候不见了呢?

这个问题比较复杂。因为View的很多属性都会影响视图的显示。解决问题的方法如下:

1. 自身原因

frame:有可能origion映射到Window上时,已经超出Window的边界了。(可以通过UIView的convert方法获取)

有可能你的width或者height中有一个为0.

hidden: 有可能某个时候hidden属性被置为YES。

alpha:有可能某个时候alpha属性被置为0.

2. superView的原因

也许你的view根本没add到superView上,或者某个时候被移除。也许是由于superView的上述“自身原因”,也许是superView的superView... 。

幸好,frame属性在Hierarchy信息中被打出, 如果hidden属性为YES,alpha为0, Hierarchy会特意打印出来。所以, 基于Hierarchy你就可以分析某个试图为什么没有正确显示的原因。

    • 场景3: 为什么我的视图(通过UIControll或者加UIGesture)点下去没反应?

这个问题很复杂,有可能它不是hitTestView, 有可能消息被UIGesture优先捕获了。这里牵涉到消息机制, 暂时不在这里说明。

但是, 下面可以针对hitTestView这个原因来进行分析。

如果它不被确定为hitTestView。 那么

1.自身原因

frame: 有可能你的width或者height为0(如果一个视图的clipsToBounds为NO时,有可能他的frame是空,但是依然能显示出来。例如UIImageView),此时hitTest方法不能判定该View能相应事件。

有可能自身的frame超出superView的frame。 那么超出部分的事件将不会将hitTestView判定给该View。这个问题比较隐蔽。也会经常遇到。

userInteractionEnabled: 为NO时,不能响应事件。

Hidden:为YES时,不能响应事件。

2.superView的原因

superView的上述“自身原因”也会影响到子View响应事件。

类似场景2. 上面的问题也可以通过查看打印的Hierarchy分析。

基于Hierarchy的UI调试方法还有通过第三方工具, 例如Hierarchy Viewer可视化工具等。

当然,通过Hierarchy还可以做更多的事情。 暂时先介绍到这里。请待下一次再进行更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值