swift - 如何在 Swift 中嵌套调试输出?

标签 swift

假设我有一个像这样的对象:

class MyClass
{
   let a_number : Int?
   let a_string : String?
   let an_array_of_strings : Array<String>?
   let an_array_of_objs : Array<Any>?
}

当我将这个对象打印到控制台时,我怎样才能使 z 像这样缩进:

MyClass
a_number            = 4
a_string            = "hello"
an_array_of_strings = ["str1",
                      "str2",
                      "str3"]
an_array_of_objs    = [MyClass
                      a_number            = 5
                      a_string            = "world"
                      an_array_of_strings = nil
                      an_array_of_objs    = nil]

最佳答案

我会用一个带有缩进累加器参数的递归函数来做到这一点。它默认为无缩进,并在每次递归调用时增加第一列的宽度:

func describe<T>(_ x: T, indent: String = "") -> String
{
    let mirror = Mirror(reflecting: x)
    guard !mirror.children.isEmpty else { return x is String ?  "\"\(x)\"" : "\(x)" }

    switch mirror.displayStyle! {
    case .tuple:
        let descriptions = mirror.children.map { describe(unwrap($0.value), indent: indent) }
        return "(" + descriptions.joined(separator: ",\n\(indent)") + ")"
    case .collection:
        let descriptions = mirror.children.map { describe(unwrap($0.value), indent: indent) }
        return "[" + descriptions.joined(separator: ",\n\(indent)") + "]"
    case .dictionary:
        let descriptions = mirror.children.map { (child: Mirror.Child) -> String in
            let entryMirrors = Array(Mirror(reflecting: unwrap(child.value)).children)
            return describe(unwrap(entryMirrors[0].value), indent: indent) + ": "
                + describe(unwrap(entryMirrors[1].value))
        }
        return "[" + descriptions.joined(separator: ",\n\(indent)") + "]"
    case .set:
        let descriptions = mirror.children.map { describe(unwrap($0.value), indent: indent) }
        return "Set(" + descriptions.joined(separator: ",\n\(indent)") + ")"
    default:
        let childrenWithLabel = mirror.children.filter { $0.label != nil }
        let separator = " = "
        let firstColumnWidth = (childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0)
            + separator.characters.count
        let subindent = indent + String(repeating: " ", count: firstColumnWidth)

        let lines = childrenWithLabel.map {
            indent
            + ($0.label! + separator).padding(toLength: firstColumnWidth, withPad: " ", startingAt: 0)
            + describe(unwrap($0.value), indent: subindent)
        }
        return (["\(mirror.subjectType)"] + lines).joined(separator: "\n")
    }
}

此函数使用来自 my answer to another questionunwrap(_:) 函数

func unwrap<T>(_ any: T) -> Any
{
    let mirror = Mirror(reflecting: any)
    guard mirror.displayStyle == .optional, let first = mirror.children.first else {
        return any
    }
    return first.value
}

当像这样使用 describe(_:) 时(我将 MyClass 设为一个结构,这样我就可以使用成员初始化器):

struct MyClass: CustomStringConvertible
{
    let a_number : Int?
    let a_string : String?
    let an_array_of_strings : Array<String>?
    let an_array_of_objs : Array<Any>?

    var description: String { return describe(self) }
}

print(MyClass(a_number: 4, a_string: "hello",
              an_array_of_strings: ["str1", "str2", "str3"],
              an_array_of_objs: [
                  MyClass(a_number: 5, a_string: "world",
                          an_array_of_strings: nil, an_array_of_objs: nil)]))

那么输出是

MyClass
a_number =            4
a_string =            "hello"
an_array_of_strings = ["str1",
                      "str2",
                      "str3"]
an_array_of_objs =    [MyClass
                      a_number =            5
                      a_string =            "world"
                      an_array_of_strings = nil
                      an_array_of_objs =    nil]

请注意,这仅通过您的特定示例和一些简单的添加进行了测试。我对 mirror.displayStyle 的强制展开也不满意,但在我的浅层测试中,这只发生在 mirror.children 为空时,前面的 守卫。如果有人对此进行了更仔细的调查,我很乐意发表评论。我没有在 Mirror 的文档中找到任何内容。

就像在 my answer to your related question 中一样我混淆了 = 应该在哪里。这次正好相反,呃! :)

关于swift - 如何在 Swift 中嵌套调试输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43336724/

相关文章:

ios - 在添加到 subview 之前如何获取 UIView 的宽度和高度?

Swift 字典默默地不存储新项目

ios - 动态设置 tableHeaderView 高度

ios - 异常 : Cannot manually set the delegate on a UINavigationBar managed by a controller

ios - NavigationBar 外观()(色调颜色..)

ios - 获取 CloudKit CKAsset URL?

ios - 如何在按钮操作中的 TableViewController 中重新加载 tableview?

swift - 在 Swift 中同步异步内容

ios - Swift 标签没有改变

swift - 如何在 Swift 中处理 CFSocketCallBackType.dataCallback?