前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swift5.8 中 AnyKeyPath 支持 CustomDebugStringConvertible 协议

Swift5.8 中 AnyKeyPath 支持 CustomDebugStringConvertible 协议

原创
作者头像
DerekYuYi
发布2022-11-10 15:43:36
6430
发布2022-11-10 15:43:36
举报
文章被收录于专栏:Swift-开源分析

该特性在 Swift 5.8 实现。提议项 SE-0369

现状

本篇提议目的是为了让AnyKeyPath支持实现CustomDebugStringConvertible协议。

先来看一下当前要解决的问题。

如果对print()或者po命令传递 keypath(key路径,下文均使用原 keypath 表述),会输出 Swift 类的标准信息。例如,我们先定义Theme struct:

代码语言:Swift
复制
struct Theme {

    var backgroundColor: UIColor
    var foregroundColor: UIColor
    
    var overlay: UIColor {
        backgroundColor.withAlphaComponent(0.8)
    }
}

再添加 keypath 执行 print(\Theme.backgroundColor), 大致输出如下:

代码语言:Swift
复制
// Swift 5.7 真实输出:
Swift.WritableKeyPath<__lldb_expr_1.Theme, __C.UIColor>

结果的关键信息包含ThemeUIColor, 但其实你无法通过结果来区分当前属性是backgroundColorforegroundColor,因为它们是同类型。所以我们期望理想的输出应该是类似这样的:

代码语言:Swift
复制
\Theme.backgroundColor

这是本篇提议想要解决的问题。

提议方案

Swift 中如果为某个类型实现CustomDebugStringConvertible协议的debugDescription方法,那么可以获得对应二进制文件中的任何可用信息。在最好的情况下,这些信息能大致产生上述输出,在最坏的情况下,也会输出其他可能有用的信息。我们需要的目标对象属性就在这些信息中。

设计细节

实现 CustomDebugStringConvertible 协议

跟目前在KeyPath.swift中实现的函数_project非常相似,该函数将循环使用 keypath 的每个缓存区,按下列方式来处理每个段(即segment):

对于偏移段,处理原理很简单:使用_getRecursiveChildCount, _getChildOffset, _getChildMetadata来获取属性的字符串类型名称,Mirror应该也可以实现该功能;

对于可选链,强制解包等,函数会适当地硬编码增加 "?" 和 "!";

对于计算段,可以对ComputedAccessorsPtrgetter方法结果调用swift::lookupSymbol(),来解析该结果并获取属性名。

Swift 运行时更改

为了实现计算段的描述,需要对 Swift 运行时做两处更改:

  1. 需要公开 Swift call-convention 函数,用来调用swift::lookupSymbol()
  2. 需要实现并暴露一个新函数来解析 keypath 函数,来代替现有的解析函数。

处理缺失数据

当前有两种已知情况下,源数据不可用:

  1. 构建 target 时,选择了swift-disable-reflection-metadata标识,导致类型元数据编译前没有提交;
  2. 链接器去掉了我们正在查找符号名称。

这两种不可用的场景下,输出的信息分别如下:

偏移场景

结果是 <offset [x] ([typename])>x从反射元数据中读取的内存偏移量,typename是将会返回的类型。所以此时打印 keypath 函数,则会输出:

代码语言:Swift
复制
print(\Theme.backgroundColor) // outputs "\Theme.<offset 0 (UIColor)>"
lookupSymbol查找失败场景

这种情况下我们打印 16进制的内存地址,并加上类型名:

代码语言:Swift
复制
print(\Theme.overlay) // outputs \Theme.<computed 0xABCDEFG (UIColor)>

这里内存地址和函数名称其实很难关联。类型名其实也无法提供准确信息,可能对其他的上下文信息提供有用处。

总结

Swift 5.8 源代码中为AnyKeyPath实现CustomDebugStringConvertible,支持 keypath 输出更详细的类型数据。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 现状
  • 提议方案
  • 设计细节
    • 实现 CustomDebugStringConvertible 协议
      • Swift 运行时更改
        • 处理缺失数据
          • 偏移场景
          • lookupSymbol查找失败场景
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档