Есть ли способ использовать вкладки для равномерного разметки строк описания в Swift?
Переопределение переменной description пользовательского класса:
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")
Кроме того, есть ли способ избавиться или сократить часть "Необязательно" и просто показать значение?
2 ответа
Я не буду использовать вкладки, но использую 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
, Смотрите этот вопрос.
Обновить
Я упустил из виду, что вы хотели иметь немного другой формат.
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
Чтобы избавиться от "необязательной" вещи, пожалуйста, смотрите мой ответ здесь.
Если вы используете (из указанного ответа) unwrap()
или же unwrapUsingProtocol()
в description
как это:
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
Попробуйте использовать этот метод. Сначала он вычисляет максимальную длину свойства, а затем использует ее для дополнения имен свойств:
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