Gibt es eine Möglichkeit, Swift-Wörterbücher hübsch auf die Konsole zu drucken?

89
NSDictionary *dictionary = @{@"A" : @"alfa",
                             @"B" : @"bravo",
                             @"C" : @"charlie",
                             @"D" : @"delta",
                             @"E" : @"echo",
                             @"F" : @"foxtrot"};
NSLog(@"%@", dictionary.description);

druckt Folgendes auf der Konsole aus:

{
    A = alfa;
    B = bravo;
    C = charlie;
    D = delta;
    E = echo;
    F = foxtrot;
}

let dictionary: [String : String] = ["A" : "alfa",
                                     "B" : "bravo",
                                     "C" : "charlie",
                                     "D" : "delta",
                                     "E" : "echo",
                                     "F" : "foxtrot"];
print(dictionary)

druckt Folgendes auf der Konsole aus:

["B": "bravo", "A": "alfa", "F": "foxtrot", "C": "charlie", "D": "delta", "E": "echo"]

Gibt es in Swift eine Möglichkeit, hübsche Druckwörterbücher zu erstellen, in denen jedes Schlüssel-Wert-Paar eine neue Zeile belegt?

Toland Hon
quelle
7
Sie können dumpbeispielsweise verwenden, wenn das Ziel darin besteht, das Wörterbuch zu überprüfen. stackoverflow.com/documentation/swift/3966/logging-in-swift/…
Eric Aya
13
print(dictionary as! NSDictionary) billiger Trick?
BaseZen
Ich bin wirklich der Vorschlag von dump (), da es nicht erforderlich ist, Code zu schreiben oder ihn zu übertragen. @EricAya, wenn Sie eine Antwort mit dieser Bemerkung posten, werde ich sie als Antwort markieren.
Toland Hon
1
@ TolHon Fertig. Ich habe eine Antwort mit einem Beispiel für die Ausgabe gegeben.
Eric Aya

Antworten:

97

Sie können beispielsweise dump verwenden , wenn das Ziel darin besteht, das Wörterbuch zu überprüfen. dumpist Teil der Standardbibliothek von Swift.

Verwendung:

let dictionary: [String : String] = ["A" : "alfa",
                                     "B" : "bravo",
                                     "C" : "charlie",
                                     "D" : "delta",
                                     "E" : "echo",
                                     "F" : "foxtrot"]

dump(dictionary)

Ausgabe:

Geben Sie hier die Bildbeschreibung ein


dump druckt den Inhalt eines Objekts durch Reflexion (Spiegelung).

Detailansicht eines Arrays:

let names = ["Joe", "Jane", "Jim", "Joyce"]
dump(names)

Drucke:

▿ 4 Elemente
- [0]: Joe
- [1]: Jane
- [2]: Jim
- [3]: Joyce

Für ein Wörterbuch:

let attributes = ["foo": 10, "bar": 33, "baz": 42]
dump(attributes)

Drucke:

▿ 3 Schlüssel / Wert-Paare
▿ [0]: (2 Elemente)
- .0: Balken
- .1: 33
▿ [1]: (2 Elemente)
- .0: baz
- .1: 42
▿ [2]: ( 2 Elemente)
- .0: foo
- .1: 10

dumpwird als deklariert dump(_:name:indent:maxDepth:maxItems:).

Der erste Parameter hat keine Bezeichnung.

Es stehen andere Parameter zur Verfügung, z. B. namedas Festlegen einer Beschriftung für das zu untersuchende Objekt:

dump(attributes, name: "mirroring")

Drucke:

▿ Spiegelung: 3 Schlüssel / Wert-Paare
▿ [0]: (2 Elemente)
- .0: Balken
- .1: 33
▿ [1]: (2 Elemente)
- .0: baz
- .1: 42
▿ [2] : (2 Elemente)
- .0: foo
- .1: 10

Sie können auch festlegen, dass nur eine bestimmte Anzahl von Elementen mit gedruckt werden soll maxItems:, dass das Objekt bis zu einer bestimmten Tiefe analysiert werden maxDepth:soll und dass die Einrückung der gedruckten Objekte mit geändert werden soll indent:.

Eric Aya
quelle
4
Dies ist kein hübsch gedruckter JSON, dies ist nur ein Dumping einer Variablen in die Konsole - kein gültiger JSON. Obwohl es den Bedürfnissen von OP entspricht, glaube ich, dass die Frage neu formuliert werden muss, um dies zu erreichen.
James Wolfe
4
@ JamesWolfe This is not pretty printed JSONNiemand hat es gesagt. Das OP fragte nach hübschen Swift-Wörterbüchern - niemand spricht über JSON, außer ein paar nicht zum Thema gehörenden Antwortenden. Bei der OP-Frage geht es überhaupt nicht um JSON.
Eric Aya
@ JamesWolfe Bitte ändern Sie auch nicht die Frage. Das wäre Vandalismus. Die Frage ist klar und es geht nicht um JSON. Ändern Sie eine Frage nicht, nur weil einige Antworten über etwas anderes sprechen. Vielen Dank.
Eric Aya
107

po Lösung

Für diejenigen unter Ihnen, die Dictionary als JSON ohne Escape-Sequenz in der Konsole sehen möchten , ist hier eine einfache Möglichkeit, dies zu tun

(lldb)p print(String(data: try! JSONSerialization.data(withJSONObject: object, options: .prettyPrinted), encoding: .utf8 )!)

Irshad Mohamed
quelle
1
Da es sich um einen Ausdruck und nicht um ein Objekt handelt, sollte es 'p' und nicht 'po' sein. Aber vielen Dank für diese Lösung! Funktioniert gut für mich
Alessandro Francucci
@AlessandroFrancucci spielt es eine Rolle? Der Befehl scheint in beiden Fällen dasselbe zu tun.
Nickjwallin
Jetzt funktionieren beide Möglichkeiten. Aber bevor ich einen "Po Print" gemacht habe, hat das bei mir nicht funktioniert. (po bedeutet Druckobjekt .... was etwas verwirrend ist, wenn Sie danach einen Druck haben und kein Objekt imho)
Alessandro Francucci
Genial! genau das, was ich brauchte, um auf nette Weise zu drucken userInfo von PushNotification
carmen_munich
107

Ein Wörterbuch in 'AnyObject' umzuwandeln war für mich die einfachste Lösung:

let dictionary = ["a":"b",
                  "c":"d",
                  "e":"f"]
print("This is the console output: \(dictionary as AnyObject)")

Dies ist die Konsolenausgabe

Dies ist für mich leichter zu lesen als die Dump-Option, aber beachten Sie, dass Sie nicht die Gesamtzahl der Schlüsselwerte erhalten.

Jalakoo
quelle
11
Es ist ein brillanter Weg und viel besser als Dump
AbdelHady
36

Nur eine andere Möglichkeit, funktionale Programmierung zu verwenden

dictionary.forEach { print("\($0): \($1)") }

Ausgabe

B: bravo
A: alfa
F: foxtrot
C: charlie
D: delta
E: echo
Luca Angeletti
quelle
1
Dies sollte die beste Antwort sein. Funktioniert perfekt!
Yuri Doubov
Oder um "noch funktionaler" zu sein ... dictionary.map {"($ 0): ($ 1)"} .forEach (print) (ironischer Kommentar)
Jon Willis
3
Dies funktioniert für das OP- [String: String]Wörterbuch, ist jedoch nicht für [AnyHashable: Any]Wörterbücher geeignet. Wenn ein Wert ein Wörterbuch ist, kehren Sie zu Swifts nicht hübschem Druck zurück.
Christopher Pickslay
Ich habe diese Antwort mit einem Buch markiert, weil ich mich immer noch nicht an diese Syntax erinnern kann
Nitin Alabur
29

Nur zum Debuggen würde ich das Array oder Wörterbuch in einen hübschen gedruckten JSON konvertieren:

public extension Collection {

    /// Convert self to JSON String.
    /// Returns: the pretty printed JSON string or an empty string if any error occur.
    func json() -> String {
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted])
            return String(data: jsonData, encoding: .utf8) ?? "{}"
        } catch {
            print("json serialization error: \(error)")
            return "{}"
        }
    }
}

Dann:

print("\nHTTP request: \(URL)\nParams: \(params.json())\n")

Ergebnis auf der Konsole:

HTTP request: https://example.com/get-data
Params: {
  "lon" : 10.8663676,
  "radius" : 111131.8046875,
  "lat" : 23.8063882,
  "index_start" : 0,
  "uid" : 1
}
Marco M.
quelle
Was ist bLog hier?
Nitesh
@Nitesh bLog ist ein einfacher benutzerdefinierter Logger mit Backtrace, den ich geschrieben und mit print () bearbeitet habe.
Marco M
Schönste Lösung.
Denis Kutlubaev
14

Ich würde nicht viele der hier gegebenen Antworten als wahrhaft gedrucktes JSON betrachten, da das Ergebnis ungültig ist, wenn Sie die Ergebnisse an einen JSON-Validator übergeben (häufig aufgrund des Codes, der '=' statt ':' enthält).

Der einfachste Weg, dies zu tun, besteht darin, das JSON-Objekt mithilfe der hübschen gedruckten Schreiboption in Daten zu konvertieren und dann eine Zeichenfolge mit den resultierenden Daten zu drucken.

Hier ist ein Beispiel:

let jsonData = try! JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)

if let jsonString = String(data: jsonData, encoding: .utf8) {
    print(jsonString)
}

Ergebnis:

{
    "jsonData": [
        "Some String"
    ],
    "moreJSONData": "Another String",
    "evenMoreJSONData": {
        "A final String": "awd"
    }
}

BEARBEITEN : Es wurde darauf hingewiesen, dass das OP nicht nach JSON gefragt hat. Ich finde jedoch, dass die Antworten, die nur das Drucken oder Ablegen der Daten in die Konsole empfehlen, nur eine sehr geringe Formatierung (falls vorhanden) bieten und daher nicht besonders druckbar sind.

Ich glaube, obwohl das OP nicht nach JSON fragt, ist es eine brauchbare Antwort, da es ein viel besser lesbares Format für Daten ist als das schreckliche Format, das von xcode / swift in die Konsole ausgespuckt wird.

James Wolfe
quelle
1
Vielen Dank, damit konnte ich während des Debuggens übere let jsonData = try! JSONSerialization.data(withJSONObject: response, options: .prettyPrinted);if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
BangOperator
5

Sie können einfach eine for-Schleife verwenden und jede Iteration drucken

for (key,value) in dictionary { 
    print("\(key) = \(value)")
}

Antrag in Erweiterung:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

    var prettyprint : String {
        for (key,value) in self {
            print("\(key) = \(value)")
        }

        return self.description
    }
}

Alternative Anwendung:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

    func prettyPrint(){
        for (key,value) in self {
            print("\(key) = \(value)")
        }
    }
}

Verwendung:

dictionary.prettyprint //var prettyprint
dictionary.prettyPrint //func prettyPrint

Ausgabe (Getestet in Xcode 8 Beta 2 Playground):

A = alfa
B = bravo
C = charlie
D = delta
E = echo
F = foxtrot
Asdrubal
quelle
1
Gibt es einen Grund, warum Sie Prettyprint zu einer Var anstatt nur zu einer Funktion gemacht haben?
Hayden Holligan
Ehrlich gesagt denke ich nicht, dass es wichtig ist (ich könnte mich irren). Aber wenn Sie es oft benutzen, ist es weniger zu tippen. Aber werfen Sie eine interessante Frage auf.
Asdrubal
3
Da es ein descriptionund debugDescriptionbereits gibt, ist es möglicherweise besser, die Variable aufzurufen prettyDescriptionund die formatierte Zeichenfolge zurückzugeben.
Toland Hon
4

Nehmen Sie für Swift 3 (und bauen Sie auf der brillanten Antwort von @Jalakoo auf ) die folgende DictionaryErweiterung auf:

extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any {
    var prettyPrint: String {
        return String(describing: self as AnyObject)
    }
}

Drucken Sie dann ein Wörterbuch einer beliebigen Hierarchie auf hübsche Weise (besser als dump()), indem Sie Folgendes verwenden:

print(dictionary!.prettyPrint)
AbdelHady
quelle
4

Die Methode zum Konvertieren des Swift Dictionary in json und zurück ist die beste. Ich benutze den Meißel von Facebook, der einen pjson- Befehl hat, um ein Swift-Wörterbuch zu drucken. Z.B:

(lldb) pjson dict as NSDictionary

Dies sollte das Wörterbuch hübsch drucken. Dies ist eine viel sauberere Methode, um das zu tun, was bereits vorgeschlagen wurde. PS Im Moment müssen Sie dikt als NSDictionary umwandeln, da die Objective-C-Laufzeit Swift-Wörterbücher nicht versteht. Ich habe bereits eine PR für Meißel erstellt, um diese Einschränkung zu beseitigen.

UPDATE: Meine PR wurde akzeptiert. Jetzt können Sie den Befehl psjson anstelle des oben genannten Befehls pjson verwenden .

Jarora
quelle
3

Einzelheiten

  • Xcode 10.2.1 (10E1001), Swift 5

Lösung

extension Dictionary {
    func format(options: JSONSerialization.WritingOptions) -> Any? {
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: self, options: options)
            return try JSONSerialization.jsonObject(with: jsonData, options: [.allowFragments])
        } catch {
            print(error.localizedDescription)
            return nil
        }
    }
}

Verwendung

let dictionary: [String : Any] = [
                                    "id": 0,
                                    "bool": true,
                                    "int_array": [1,3,5],
                                    "dict_array": [
                                        ["id": 1, "text": "text1"],
                                        ["id": 1, "text": "text2"]
                                    ]
                                 ]
print("Regualr print:\n\(dictionary)\n")
guard let formatedDictionary = dictionary.format(options: [.prettyPrinted, .sortedKeys]) else { return }
print("Pretty printed:\n\(formatedDictionary)\n")

Ergebnisse

Geben Sie hier die Bildbeschreibung ein

Wassili Bodnarchuk
quelle
1

Swift 5, Xcode 10.3:

po print(<your Plist container>)
Über die Ukraine
quelle
1

Hübscher Druck vom Datenobjekt:

let jsonObj = try JSONSerialization.jsonObject(with: data, options: [])
            let jsonData = try JSONSerialization.data(withJSONObject: jsonObj, options: [.prettyPrinted])
            print(String(data: jsonData, encoding: .utf8)!)
Hugo Jordao
quelle
0

Wie wäre es mit:

import Foundation

extension Dictionary {
    var myDesc: String {
        get {
            var v = ""
            for (key, value) in self {
                v += ("\(key) = \(value)\n")
            }
            return v
        }
    }
}


// Then, later, for any dictionary:
print(dictionary.myDesc)
BaseZen
quelle
0
extension String {

    var conslePrintString: String {

        guard let data = "\""
            .appending(
                replacingOccurrences(of: "\\u", with: "\\U")
                    .replacingOccurrences(of: "\"", with: "\\\"")
            )
            .appending("\"")
            .data(using: .utf8) else {

            return self
        }

        guard let propertyList = try? PropertyListSerialization.propertyList(from: data,
                                                                             options: [],
                                                                             format: nil) else {
            return self
        }

        guard let string = propertyList as? String else {
            return self
        }

        return string.replacingOccurrences(of: "\\r\\n", with: "\n")
    }
}

let code in extension String and it works fine 

let string = "\(jsonDictionary)".conslePrintString
hasayakey
quelle
0

Geben Sie beim Debuggen die Struktur aus, die dem Codable Protocol für die Konsole entspricht, und
verwenden Sie das JSON-Format.

extension Encodable {
    var jsonData: Data? {
        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        return try? encoder.encode(self)
    }
}

extension Encodable where Self: CustomDebugStringConvertible {
    var debugDescription: String {
         if let data = self.jsonData,
             let string = String(data: data, encoding: .utf8) {
             return string
         }
         return "can not convert to json string"
     }
}

strcut konform CustomDebugStringConvertible

struct Test: Codable, CustomDebugStringConvertible {
    let a: String
    let b: Int
}

let t = Test(a: "test string", b: 30)

Debug-Druckstruktur

(lldb) p print(t)
{
  "a" : "test string",
  "b" : 30
}
wlixcc
quelle