Is there a way to use tabs to evenly space out description strings in Swift?
I wouldn't use tabs but use 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")
}
For a struct like
struct Foo: CustomStringConvertible
{
let userID = 42
let username = "Foo"
let verylongpropertyname: String? = "Bar"
}
this produces
userID = 42
username = Foo
verylongpropertyname = Optional("Bar")
As for the "Optional" part, it's not as easy as totiG suggests because the value you get from the mirror is of type Any
. See this question.
Update
I overlooked that you wanted to have a slightly different format.
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)"
}
}
produces
userID = 42
username = Foo
verylongpropertyname = Optional("Bar")
Update 2
To get rid of the "Optional" thing, please see my answer here.
If you use (from said answer) unwrap()
or unwrapUsingProtocol()
in description
like this:
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")
}
this will produce
userID = 42
username = Foo
verylongpropertyname = Bar
How can I nest debug output in Swift?
I'd do that with a recursive function with an accumulator parameter for the indentation. It defaults to no indentation and is increased by the first column's width on each recursive call:
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")
}
}
This function uses the unwrap(_:)
function from my answer to another question
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
}
When using describe(_:)
like this (I made MyClass
a struct so I can use the memberwise initializer):
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)]))
then the output is
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]
Please note that this is only tested with your specific example and some simple additions. I am also not happy about the forced unwrap of mirror.displayStyle
but in my shallow testing this only ever happened when mirror.children
is empty, which is covered by the preceding guard
. If anybody has investigated this more closely, I'd love a comment. I haven't found anything in the documentation of Mirror
.
And just like in my answer to your related question I mixed up where the =
is supposed to be. Just the other way round this time, duh! :)
Is there any proper way to fill equally labels in stack view?
Solved my problem by putting label into the view container.
Generating a table with columns of equal width (viewed on the console in Xcode)
Try this:
for i in 0...11 {
let month = (months[i] as NSString).UTF8String
println(String(format:"%-10s %10d %10d %10d", month,
rainfall[i], raindays[i], water_deficit[i]))
}
For details un format and format specifiers see here and here.
In let month = (months[i] as NSString).UTF8String
I am applying a conversion from String to C String: it is pretty easy to specify a length in the format specifier of a C String, but I don't know how to do it for a String (my guess is that it is not possible).
How can I indent multiple lines in Xcode?
The keyboard shortcuts are ⌘+] for indent and ⌘+[ for un-indent.
- In Xcode's preferences window, click the Key Bindings toolbar button. The Key Bindings section is where you customize keyboard shortcuts.
Split a String into an array in Swift?
The Swift way is to use the global split
function, like so:
var fullName = "First Last"
var fullNameArr = split(fullName) {$0 == " "}
var firstName: String = fullNameArr[0]
var lastName: String? = fullNameArr.count > 1 ? fullNameArr[1] : nil
with Swift 2
In Swift 2 the use of split becomes a bit more complicated due to the introduction of the internal CharacterView type. This means that String no longer adopts the SequenceType or CollectionType protocols and you must instead use the .characters
property to access a CharacterView type representation of a String instance. (Note: CharacterView does adopt SequenceType and CollectionType protocols).
let fullName = "First Last"
let fullNameArr = fullName.characters.split{$0 == " "}.map(String.init)
// or simply:
// let fullNameArr = fullName.characters.split{" "}.map(String.init)
fullNameArr[0] // First
fullNameArr[1] // Last
Related Topics
Way to Purge All But One Object Types (Models) in a Realm
Decode Dictionary with Random Initial Key
Cast Any to Float Always Fails in Swift4.1
Resizing Uimage When Using Sf Symbols - Uiimage(Systemname:)
Need Explanation About Random Function Swift
Swiftui on MACos - Handle Single-Click and Double-Click at the Same Time
Observe Progress of Data Download in Swift
Filteredarrayusingpredicate Does Not Exist in Swift Array
Get the First Day of Week Without Weekcalendarunit
Swift Delegate Beetween Two Vc Without Segue
Swift Skshapenode Shapewithsplinepoints
How to Convert Dispatchtimeinterval to Nstimeinterval (Or Double)
Does the Initializer of an 'Open' Class Need to Be Open as Well
How to Open a Url in Safari Even If My Default Browser Is Not Safari Using Swift in MACos
Using Foreach with a String Array - [String] Has No Member 'Identified'