是谁吃掉了你的点击事件?
in 技术 with 0 comment

是谁吃掉了你的点击事件?

in 技术 with 0 comment

在我们遇到的问题中,事件无法响应算是常客了。有时候甚至花费数小时排查这种问题,其效率低得让人发指。后来决定沉下心来,专心研究一种科学的办法,帮助我们可以快速定位问题。

理解

要想深入了解其原理,非常推荐这篇文章。这里我就不做过多解释。

我们只需要知道事件是由 UIApplication 调用其 sendEvent 方法把事件传递给 keyWindowkeyWindow 调用其 sendEvent 方法把事件传递给响应的视图。

- (void)sendEvent:(UIEvent *)event;

额外的,发现文档里面的属性 keyWindow 将要被 Deprecated,兼容性为 iOS 2.0–13.0。但是并不影响我们,我们只需要用到 UIWindow 类而已。

Debug

根据上面的关键点,我们可以在 Xcode 里面添加 Symbolic Breakpoint,具体配置见下图:

Snipaste_2020-07-30_18-41-14.png

你可能会问,为什么不用 -[UIApplication sendEvent:],但是这样你除了能得到 window 的信息,其它一无所获。至于下面的 po $arg3 的意思是为了打印 event 参数,可以参考如下说明:

$arg3$argn — represents the parameters sent to that function.

继续执行你的事件操作,这个时候控制台会输出如下信息:

<UITouchesEvent: 0x60000355cd80> timestamp: 984803 touches: {(
    <UITouch: 0x7f8743c13750> phase: Ended tap count: 1 force:  <TestEventTouch.CView: 0x7f8744a14f40; frame = ...
)}

你可以很容易的获取到是类名为 CView 的视图吃了你的事件。

但是

如果类名为 UIView 或者 NSView 怎么办?并不是所有的视图都是自定义视图类,这可要海底捞针了!
这个时候需要借助于 pviews 这个命令,不过先等等,要用这个命令你还需要做一些准备工作。

chisel

chisel 这是一个 Facebook 用 Python 编写的 LLDB 命令集合。按照 Github 上面的步骤安装即可。不过最后如果你的目录 /usr/local/opt/chisel/libexec 里面如果没有 fbchisellldb.py 的话,可以用 fblldb.py 代替。话说这是不是 Facebook 挖的又一坑...

重启你的 Xcode 后,取消上面断点 Automatically continue after ... 的勾选, 执行点击并且断点以后,利用 pviews 后面跟上 UIView 对象的指针地址,即可查看当前视图的层级信息。比如 pviews 0x7f8744a14f40,控制台则会打印:

<UIView: 0x7f8744a14f40; 
   | <TestGoodsImageView: 0x120979c10; baseClass = UIView; 
   |    | <UIView: 0x120977ff0; 
   |    |    | <TestGoodsImageView: 0x12097bcf0; baseClass = UIImageView; 
   | <TestGoodsImageView: 0x1209892d0; baseClass = UIView; 
   |    | <UIView: 0x1209894d0; 
   |    |    | <TestGoodsImageView: 0x120989c50; baseClass = UIImageView;

这样定位起来就更加简单了。

Responses