Apakah ada cara untuk mencetak kamus Swift dengan cantik ke konsol?


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

mencetak yang berikut ini di konsol:

{
    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)

mencetak yang berikut ini di konsol:

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

Apakah ada cara di Swift untuk membuatnya menjadi kamus cetak yang cantik di mana setiap pasangan nilai kunci menempati baris baru?


8
Anda dapat menggunakan dump, misalnya, jika tujuannya adalah untuk memeriksa kamus. stackoverflow.com/documentation/swift/3966/logging-in-swift/…
Eric Aya

14
print(dictionary as! NSDictionary) Trik murahan?
BaseZen

Saya benar-benar saran dump () karena tidak perlu menulis kode apa pun atau membuangnya. @EricAya, jika Anda memposting jawaban dengan komentar itu, saya akan menandainya sebagai jawabannya.
Toland Hon

1
Selesai. Saya telah membuat jawaban dengan contoh output.
Eric Aya

Jawaban:


100

Anda dapat menggunakan dump , misalnya, jika tujuannya adalah untuk memeriksa kamus. dumpadalah bagian dari pustaka standar Swift.

Pemakaian:

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

dump(dictionary)

Keluaran:

masukkan deskripsi gambar di sini


dump mencetak isi suatu objek melalui refleksi (mirroring).

Tampilan rinci dari sebuah larik:

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

Cetakan:

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

Untuk kamus:

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

Cetakan:

▿ 3 pasangan kunci / nilai
▿ [0]: (2 elemen)
- .0: bar
- .1: 33
▿ [1]: (2 elemen)
- .0: baz
- .1: 42
▿ [2]: ( 2 elemen)
- .0: foo
- .1: 10

dumpdideklarasikan sebagai dump(_:name:indent:maxDepth:maxItems:).

Parameter pertama tidak memiliki label.

Ada parameter lain yang tersedia, seperti namemenyetel label untuk objek yang akan diperiksa:

dump(attributes, name: "mirroring")

Cetakan:

▿ pencerminan: 3 pasangan kunci / nilai
▿ [0]: (2 elemen)
- .0: batang
- .1: 33
▿ [1]: (2 elemen)
- .0: baz
- .1: 42
▿ [2] : (2 elemen)
- .0: foo
- .1: 10

Anda juga dapat memilih untuk mencetak hanya sejumlah item tertentu dengan maxItems:, untuk mengurai objek hingga kedalaman tertentu dengan maxDepth:, dan untuk mengubah indentasi objek yang dicetak dengan indent:.


5
Ini bukan JSON yang dicetak dengan cantik, ini hanya membuang variabel ke konsol - bukan JSON yang valid. Meskipun memang sesuai dengan kebutuhan OP, saya yakin pertanyaannya perlu disusun ulang agar sesuai dengan ini.
James Wolfe

4
@JamesWolfe This is not pretty printed JSONTidak ada yang mengatakan itu. OP bertanya tentang pencetakan kamus Swift yang cantik - tidak ada yang membicarakan tentang JSON, kecuali beberapa penjawab di luar topik. Pertanyaan OP sama sekali bukan tentang JSON.
Eric Aya

@JamesWolfe Juga tolong jangan ubah pertanyaannya. Itu akan menjadi vandalisme. Pertanyaannya jelas, dan ini bukan tentang JSON. Jangan mengubah pertanyaan hanya karena beberapa jawaban berbicara tentang hal lain. Terima kasih.
Eric Aya

112

Mentransmisikan kamus ke 'AnyObject' adalah solusi paling sederhana bagi saya:

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

ini adalah keluaran konsol

Bagi saya ini lebih mudah dibaca daripada opsi dump, tetapi perhatikan itu tidak akan memberi Anda jumlah total nilai kunci.


11
Ini adalah cara yang brilian dan jauh lebih baik daripada membuang
AbdelHady

109

solusi po

Bagi Anda yang ingin melihat Dictionary sebagai JSON tanpa escape sequence di konsol , berikut adalah cara sederhana untuk melakukannya

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

Memperbarui

Periksa jawaban ini juga. Jawab


1
Karena merupakan ekspresi dan bukan objek, itu harus 'p' dan bukan 'po'. Tapi terima kasih banyak atas solusi ini! Bekerja dengan baik untuk saya
Alessandro Francucci

@AlessandroFrancucci apakah itu penting? Perintah tersebut tampaknya melakukan hal yang sama dengan cara apa pun.
nickjwallin

Sekarang kedua cara melakukannya berhasil. Tapi sebelum melakukan "cetak po" tidak berhasil untuk saya. (po berarti objek cetak .... yang agak membingungkan jika Anda memiliki cetakan sesudahnya dan bukan objek imho)
Alessandro Francucci

Hebat! hanya apa yang saya butuhkan untuk mencetak dengan cara yang bagus userInfo dari PushNotification
carmen_munich

1
Periksa komentar ini untuk memanfaatkan ini dalam alias lldb sehingga Anda tidak perlu mengetiknya setiap saat!
Agirault

36

Hanya cara lain menggunakan Pemrograman Fungsional

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

Keluaran

B: bravo
A: alfa
F: foxtrot
C: charlie
D: delta
E: echo

1
Ini harus menjadi jawaban teratas. Bekerja dengan sempurna!
Yuri Doubov

Atau untuk menjadi "bahkan lebih fungsional" ... dictionary.map {"($ 0): ($ 1)"} .forEach (print) (komentar lidah-di-pipi)
Jon Willis

3
Ini berfungsi untuk [String: String]kamus OP , tetapi tidak bagus untuk [AnyHashable: Any]kamus, di mana jika nilainya adalah kamus, Anda kembali ke pencetakan Swift yang tidak bagus.
Christopher Pickslay

Saya memiliki buku yang menandai jawaban ini🙂, karena saya masih tidak dapat mengingat sintaks ini 🙄
Nitin Alabur

29

Untuk tujuan debug saja saya akan mengonversi Array atau Dictionary ke json yang cukup dicetak:

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 "{}"
        }
    }
}

Kemudian:

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

Hasil di konsol:

HTTP request: https://example.com/get-data
Params: {
  "lon" : 10.8663676,
  "radius" : 111131.8046875,
  "lat" : 23.8063882,
  "index_start" : 0,
  "uid" : 1
}

apa bLog disini?
Nitesh

@Nitesh bLog adalah custom logger sederhana dengan backtrace yang saya tulis, diedit dengan print ().
Marco M

Solusi terindah.
Denis Kutlubaev

Jika Anda ingin menghindari penambahan potongan kode itu di setiap proyek Anda, Anda dapat memanfaatkan kode itu dengan alias lldb untuk dengan mudah menghitung json di terminal debug (detailnya di sini ).
Agirault

14

Saya tidak akan menganggap banyak jawaban yang diberikan di sini benar JSON yang cukup dicetak, karena ketika Anda meneruskan hasilnya ke validator JSON, hasilnya tidak valid (seringkali karena kode termasuk '=' daripada ':').

Cara termudah yang saya temukan untuk melakukan ini hanyalah mengonversi objek JSON menjadi data menggunakan opsi tulisan yang cukup dicetak kemudian mencetak string menggunakan data yang dihasilkan.

Berikut ini contohnya:

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

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

Hasil:

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

EDIT : Telah ditunjukkan bahwa OP tidak meminta JSON, namun saya menemukan bahwa jawaban yang merekomendasikan hanya mencetak atau membuang data ke konsol memberikan format yang sangat sedikit (jika ada) dan karena itu tidak cukup mencetak.

Saya percaya bahwa meskipun OP tidak meminta JSON, ini adalah jawaban yang layak karena ini adalah format data yang jauh lebih mudah dibaca daripada format menghebohkan yang dimuntahkan ke konsol oleh xcode / swift.


1
Terima kasih, Dengan ini saya dapat mencetak dengan cantik selama debugging melalui e let jsonData = try! JSONSerialization.data(withJSONObject: response, options: .prettyPrinted);if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
BangOperator

1
Ini bagus! Anda dapat memanfaatkan kode ini dengan alias lldb untuk dengan mudah menghitung json di terminal debug (detailnya di sini ).
Agirault

5

Anda bisa menggunakan for loop dan mencetak setiap iterasi

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

Aplikasi dalam ekstensi:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

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

        return self.description
    }
}

Aplikasi alternatif:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

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

Pemakaian:

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

Output (Diuji di Xcode 8 beta 2 Playground):

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

1
Apakah ada alasan mengapa Anda menjadikan prettyprint sebagai var dan bukan hanya sebuah fungsi?
Hayden Holligan

Sejujurnya, saya tidak berpikir itu penting (saya bisa saja salah). Tetapi jika Anda sering menggunakannya maka itu kurang untuk diketik. Tapi ajukan pertanyaan yang menarik.
Asdrubal

3
Karena sudah ada descriptiondan debugDescription, mungkin lebih tepat untuk memanggil var prettyDescriptiondan mengembalikan string yang telah diformat.
Toland Hon

5

Metodologi untuk mengubah Swift Dictionary ke json dan back adalah yang paling rapi. Saya menggunakan pahat Facebook yang memiliki perintah pjson untuk mencetak kamus Swift. Misalnya:

(lldb) pjson dict as NSDictionary

Ini harus mencetak kamus dengan cantik. Ini adalah cara yang jauh lebih bersih untuk melakukan apa yang telah disarankan. PS Untuk saat ini, Anda harus menggunakan dict sebagai NSDictionary karena runtime Objective-C tidak memahami kamus Swift. Saya telah menaikkan PR di atas pahat untuk menghilangkan batasan itu.

PEMBARUAN: PR saya diterima. Sekarang Anda dapat menggunakan perintah psjson sebagai pengganti pjson yang disebutkan di atas.


4

Untuk Swift 3 (& membangun jawaban brilian dari @Jalakoo ), buat Dictionaryekstensi berikut :

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

lalu cetak kamus dari hierarki apa pun dengan cara yang cantik (lebih baik dari dump()) menggunakan ini:

print(dictionary!.prettyPrint)

4

Detail

  • Xcode 10.2.1 (10E1001), Swift 5

Larutan

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
        }
    }
}

Pemakaian

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")

Hasil

masukkan deskripsi gambar di sini


3

Disesuaikan berdasarkan jawaban saya yang lain di sini .

Solusi PrettyPrint JSON menggunakan alias LLDB

Tidak perlu kode

  • Untuk mendapatkan format json yang bagus (lekukan, baris baru, dll) Anda dapat mendefinisikan alias lldb dengan menjalankan perintah ini di terminal lldb Anda ( sumber ):
command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'
  • Anda mungkin tidak ingin mendefinisikan ulang alias setiap kali Anda membuka XCode, jadi jalankan perintah berikut untuk menambahkan definisi alias ke ~/.lldbinit:
echo "command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'" >> ~/.lldbinit
  • Ini akan membuat pjsonalias yang dapat Anda gunakan di terminal lldb Anda di XCode:
pjson object

Membandingkan keluaran untuk objek Swift berikut:

// Using Any? to demo optional & arbitrary Type
let dictionary: Any? = [
    "embedded": [
        "JustForTheSakeOfTheDemo": 42
    ],
    "A" : "alfa",
    "B" : "bravo",
    "C" : "charlie",
    "D" : "delta",
    "E" : "echo",
    "F" : "foxtrot"
]

✅ Output dari pjson dictionary

{
  "F" : "foxtrot",
  "D" : "delta",
  "embedded" : {
    "JustForTheSakeOfTheDemo" : 42
  },
  "E" : "echo",
  "A" : "alfa",
  "C" : "charlie",
  "B" : "bravo"
}

❌ Output dari p dictionary

(Any?) $R0 = 7 key/value pairs {
  [0] = {
    key = "F"
    value = "foxtrot"
  }
  [1] = {
    key = "D"
    value = "delta"
  }
  [2] = {
    key = "embedded"
    value = 1 key/value pair {
      [0] = (key = "JustForTheSakeOfTheDemo", value = 42)
    }
  }
  [3] = {
    key = "E"
    value = "echo"
  }
  [4] = {
    key = "A"
    value = "alfa"
  }
  [5] = {
    key = "C"
    value = "charlie"
  }
  [6] = {
    key = "B"
    value = "bravo"
  }
}

❌ Output dari p (dictionary as! NSDictionary)

(NSDictionary) $R18 = 0x0000000281e89710 {
  ObjectiveC.NSObject = {
    base__SwiftNativeNSDictionaryBase@0 = {
      baseNSDictionary@0 = {
        NSObject = {
          isa = Swift._SwiftDeferredNSDictionary<Swift.String, Any> with unmangled suffix "$"
        }
      }
    }
  }
}

❌ Output dari po dictionary

Optional<Any>
  ▿ some : 7 elements
    ▿ 0 : 2 elements
      - key : "F"
      - value : "foxtrot"1 : 2 elements
      - key : "D"
      - value : "delta"2 : 2 elements
      - key : "embedded"
      ▿ value : 1 element
        ▿ 0 : 2 elements
          - key : "JustForTheSakeOfTheDemo"
          - value : 423 : 2 elements
      - key : "E"
      - value : "echo"4 : 2 elements
      - key : "A"
      - value : "alfa"5 : 2 elements
      - key : "C"
      - value : "charlie"6 : 2 elements
      - key : "B"
      - value : "bravo"

❌ Output dari po print(dictionary)

Optional(["F": "foxtrot", "D": "delta", "embedded": ["JustForTheSakeOfTheDemo": 42], "E": "echo", "A": "alfa", "C": "charlie", "B": "bravo"])


1

Saat debugging, keluarkan struct yang sesuai dengan Codable Protocol ke konsol
menggunakan format json.

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 sesuai dengan CustomDebugStringConvertible

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

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

debug print struct

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

1

Cukup cetak dari objek Data:

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

1
Ini bagus! Anda dapat memanfaatkan kode ini dengan alias lldb untuk dengan mudah menghitung json di terminal debug (detailnya di sini ).
Agirault

0

Bagaimana tentang:

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)

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.