Kealdish's Studio.

Kealdish's Studio.

just focus

Mach-O 文件解析

0x00 概要

Mach-OMach object 文件格式的缩写,它是一种用于记录可执行文件、对象代码、共享库、动态加载代码和内存转储的文件格式。作为 a.out 格式的替代品, Mach-O 提供了更好的扩展性,并提升了符号表中信息的访问速度。

每个 Mach-O 文件都包含一个 Mach-O 头,然后是载入命令(Load Commands),最后是数据块(Data)。

为 Objective-C 下的 protocol 添加默认实现

最近有业务有需求需要为 UIViewControllerUIViewControllerTransitioningDelegate 协议提供默认的实现,使用 swift 开发默认是支持给协议添加默认实现的,但是,目前主项目中使用的是 Objective-C 做开发,而 Objective-C 下是不支持给协议添加默认实现的。调研一番后,找到了合适的解决方案—— PKProtocolExtension

原理解析

宏定义

PKProtocolExtension.h 中的内容如下:

反射如何工作

原文地址 https://swift.org/blog/how-mirror-works/?utm_source=mybridge&utm_medium=blog&utm_campaign=read_more

虽然 swift 是一门特别强调静态类型的语言,但是它同时也支持丰富的元数据类型,也就是说允许在运行时检查代码和操作任意值。这种特性通过 Mirror API 暴露给开发人员。你可能会很好奇,Mirror 是如何在如此强调静态类型的语言中工作的?让我们来一探究竟。

免责声明

接下来所讲得内容是内部实现的细节,所涉及的代码是在当前版本中的写法,在将来可能会发生改变。当 ABI 稳定后,元数据将变成固定和可信赖的格式,但是现在它仍会发生改变。如果你写常规的 swift 代码,不要依赖于元数据。如果你要编写的代码所要实现的是比 Mirror API 所提供的更复杂的反射机制的话,本篇文章将会启发你它们是如何一起配合的,但是要记住所有一切在未来都可能发生改变。

接口

Mirror(reflecting:) 初始化器得参数接受任意值。返回的 Mirror 实例提供关于这个值的信息,主要是它所包含的子项。每个子项包含一个值和一个可选的标签。然后,你就可以在不需要知道编译时的任何类型信息的情况下,使用 Mirror 去遍历一个对象的所有子项。

Mirror 允许类型在遵守 CustomReflectable 协议的条件下,提供自定义的表现。这种特性对于那些希望展示比从内省中获得更多信息的类来说是特别有用的。例如,Array 遵守 CustomReflectable 协议并且将所有的元素暴露为未标签化的子项。 Dictionary 使用这种特性将所有的键值对暴露为标签化的子项。

对于所有其他的类型而言, Mirror 在值的真实内容基础上做了一些魔法操作生成一列子项。对于结构体和类而言,它将存储的属性作为子项展示。对于元组而言,它展示的是元组的元素。枚举则是展示每种情况和其对应的值(如果有的话)。

黑魔法是如何工作的?让我们来看一看。

利用 KVO 解决 swizzle 失效问题

最近碰到一个需求,类似于下图所示,几个 UIButton 排列在一起,在某个事件触发时,隐藏或者显示中间的 button ,重点是隐藏中间的 button 时,上下 button 之间的间距保持为原来的间距。比较好的做法是重写 alignmentRectInsets 的 get 方法,当然更新约束的方法也是 OK 的。直接创建子类去重写 alignmentRectInsets 的 get 方法不够优雅,因而想到创建分类, swizzle UIViewalignmentRectInsets 的 get 方法,在自己的自定义方法中去完成真正的修改逻辑。

原以为写完分类,在项目中调用再 run 一下就大功告成了,然而,我还是 naive 啊。运行项目后,发现竟然没有 work ,打断点调试,发现 swizzle method 没有调用。没有调用的原因在于 UIButton 类本身的实现已经重写了 alignmentRectInsets 的 get 方法,所以,不会再调用 UIView 的相同方法了。那怎么办呢?最简单的办法就是给 UIButton 创建分类而不是 UIView ,但是感觉这样写不是很好,有些冗余。

经过一番研究后,想到可以利用 KVO 的机制来解决这个问题。

探究 iOS 11 下的 UIDebuggingInformationOverlay

前言

自 iOS 9 以后,Apple 加入了悬浮窗调试工具,也就是 UIDebuggingInformationOverlay 。利用它我们可以做到很多事情,例如:查看视图层级,控制器层级,页面中的变量,测量等等。那么我们如何开启这个调试工具呢?只需要添加如下的代码:

1
2
3
4
let overlayClass = NSClassFromString("UIDebuggingInformationOverlay") as? UIWindow.Type
_ = overlayClass?.perform(NSSelectorFromString("prepareDebuggingOverlay"))
let overlay = overlayClass?.perform(NSSelectorFromString("overlay")).takeUnretainedValue() as? UIWindow
_ = overlay?.perform(NSSelectorFromString("toggleVisibility"))

这段代码的实际意义可以转换成以下两行代码:

1
2
[UIDebuggingInformationOverlay prepareDebuggingOverlay];
[[UIDebuggingInformationOverlay overlay] toggleVisibility];

调用成功后,我们就能看到悬浮窗的庐山真面目了。

avatar
Kealdish
Hear my roar.
FRIENDS