【问题标题】:Is there a way to use tabs to evenly space out description strings in Swift?有没有办法使用制表符在 Swift 中均匀地隔开描述字符串?
【发布时间】:2017-04-07 07:18:00
【问题描述】:

覆盖自定义类的描述变量:

override var description : String {
        let mirrored_object = Mirror(reflecting: self)
        let str:NSMutableString = NSMutableString()
        for (index, attr) in mirrored_object.children.enumerated() {
            if let property_name = attr.label as String! {
                //str.append(" Attr \(index): \(property_name) = \(attr.value)\n")
                str.append("\t\(property_name) = \t\t\(attr.value)\n")
            }
        }
        return str as String
    }

产生如下所示的输出:

userID =        Optional(0)
username =          Optional("testuser")
email =         Optional("test@gmail.com")

有没有办法在输出中设置选项卡,以便属性值像这样排列整齐?

userID =        Optional(0)
username =      Optional("testuser")
email =         Optional("test@gmail.com")

另外,有什么办法可以去掉或缩短“可选”部分,只显示值?

【问题讨论】:

  • 为了摆脱可选部分,使用空合并运算符避免需要解包。所以把 (attr.value) 改成 (attr.value ?? "")

标签: swift debugging


【解决方案1】:

我不会使用标签,而是使用padding(...)

var description : String {
    let mirrored_object = Mirror(reflecting: self)
    let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
    let maxLen = childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0
    let lines = childrenWithLabel.map { $0.label!.padding(toLength: maxLen, withPad: " ", startingAt: 0) + " = \($0.value)" }
    return lines.joined(separator: "\n")
}

对于像这样的结构

struct Foo: CustomStringConvertible
{
    let userID = 42
    let username = "Foo"
    let verylongpropertyname: String? = "Bar"
}

这会产生

userID               = 42
username             = Foo
verylongpropertyname = Optional("Bar")

至于“可选”部分,它并不像totiG 建议的那么简单,因为您从镜像中获得的值是Any 类型。见this question

更新

我忽略了您想要稍微不同的格式。

var description : String {
    let mirrored_object = Mirror(reflecting: self)
    let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
    let separator = " = "
    let firstColumnWidth = (childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0) + separator.characters.count
    let lines = childrenWithLabel.map {
        ($0.label! + separator).padding(toLength: firstColumnWidth, withPad: " ", startingAt: 0) + "\($0.value)"
    }
}

生产

userID =               42
username =             Foo
verylongpropertyname = Optional("Bar")

更新 2

要摆脱“可选”的东西,请参阅my answer here

如果您在description 中使用(来自上述答案)unwrap()unwrapUsingProtocol(),如下所示:

var description : String {
    let mirrored_object = Mirror(reflecting: self)
    let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
    let separator = " = "
    let firstColumnWidth = (childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0) + separator.characters.count
    let lines = childrenWithLabel.map {
        ($0.label! + separator).padding(toLength: firstColumnWidth, withPad: " ", startingAt: 0) + "\(unwrap($0.value))"
    }
    return lines.joined(separator: "\n")
}

这会产生

userID =               42
username =             Foo
verylongpropertyname = Bar

【讨论】:

  • 该链接中的解包解决方案对我不起作用,但这回答了格式化我的描述的主要问题。
  • @GoldenJoe 我自己添加了对我链接到的问题的答案,并在此处进行了第二次更新,现在这对你有用吗?
  • 太棒了。非常感谢!我要补充一点,您必须继承 NSObject 并覆盖描述才能使其工作。既然我有你的耳朵,我会向你指出我的下一个问题:stackoverflow.com/questions/43336724/…
  • @GoldenJoe 要么,要么你做任何你想打印的东西CustomStringConvertible,比如上面的struct Foo
【解决方案2】:

尝试使用此方法。它首先计算属性的最大长度,然后用它来填充属性名称:

let maxPropertyLength: Int = mirrored_object.children.map { Int($0.label?.characters.count ?? 0) }.max() ?? 0
for attr in mirrored_object.children {
    if let propertyName = attr.label {
        str.append("\(propertyName.padding(toLength: maxPropertyLength + 2, withPad: " ", startingAt: 0)) = \(attr.value)\n")
    }
}
return str as String

【讨论】:

    猜你喜欢
    • 2014-04-15
    • 1970-01-01
    • 2018-03-31
    • 2011-07-15
    • 2020-10-24
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多