Swift sözlüklerini konsola güzelce yazdırmanın bir yolu var mı?


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

konsolda aşağıdakileri yazdırır:

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

konsolda aşağıdakileri yazdırır:

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

Swift'de, her bir anahtar / değer çiftinin yeni bir satırda yer aldığı güzel basılı sözlüklere ulaşmanın bir yolu var mı?


7
Sen kullanabilirsiniz dumpgol sözlüğü incelemek için ise, örneğin,. stackoverflow.com/documentation/swift/3966/logging-in-swift/…
Eric Aya

13
print(dictionary as! NSDictionary) ucuz numara?
BaseZen

Ben gerçekten dump () önerisiyim çünkü herhangi bir kod yazmayı veya onu yayınlamayı gerektirmez. @EricAya, bu yorumla bir cevap gönderirsen, cevap olarak işaretlerim.
Toland Hon

1
@TolandHon Bitti. Çıktının bir örneği ile cevap verdim.
Eric Aya

Yanıtlar:


99

Örneğin amaç sözlüğü incelemekse dökümü kullanabilirsiniz . dumpSwift'in standart kitaplığının bir parçasıdır.

Kullanım:

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

dump(dictionary)

Çıktı:

görüntü açıklamasını buraya girin


dump bir nesnenin içeriğini yansıtma (aynalama) yoluyla yazdırır.

Bir dizinin ayrıntılı görünümü:

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

Baskılar:

▿ 4 öğe
- [0]: Joe
- [1]: Jane
- [2]: Jim
- [3]: Joyce

Sözlük için:

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

Baskılar:

▿ 3 anahtar / değer çifti
▿ [0]: (2 öğe)
- .0: bar
- .1: 33
▿ [1]: (2 öğe)
- .0: baz
- .1: 42
▿ [2]: ( 2 eleman)
- .0: foo
- .1: 10

dumpolarak ilan edilir dump(_:name:indent:maxDepth:maxItems:).

İlk parametrenin etiketi yoktur.

nameİncelenen nesne için bir etiket ayarlamak gibi başka parametreler de mevcuttur :

dump(attributes, name: "mirroring")

Baskılar:

▿ yansıtma: 3 anahtar / değer çifti
▿ [0]: (2 öğe)
- .0: bar
- .1: 33
▿ [1]: (2 öğe)
- .0: baz
- .1: 42
▿ [2] : (2 öğe)
- .0: foo
- .1: 10

Ayrıca yalnızca belirli sayıda öğeyi ile yazdırmayı maxItems:, nesneyi belirli bir derinliğe kadar ayrıştırmayı ve maxDepth:yazdırılan nesnelerin girintisini ile değiştirmeyi de seçebilirsiniz indent:.


5
Bu oldukça basılı bir JSON değil, bu sadece konsola aa değişkenini atıyor - geçerli JSON değil. OP'nin ihtiyaçlarına uygun olsa da, sorunun buna uyması için yeniden ifade edilmesi gerektiğine inanıyorum.
James Wolfe

4
@JamesWolfe This is not pretty printed JSONKimse öyle olduğunu söylemedi. OP, Swift sözlüklerinin oldukça basılması hakkında sorular sordu - konu dışı birkaç cevaplayıcı dışında kimse JSON hakkında konuşmuyor. OP'nin sorusu JSON ile ilgili değil.
Eric Aya

@JamesWolfe Ayrıca lütfen soruyu değiştirmeyin. Bu vandalizm olur. Soru olduğu gibi açık ve JSON ile ilgili değil. Bir soruyu sırf bazı cevaplar başka bir şey hakkında konuşuyor diye değiştirmeyin. Teşekkürler.
Eric Aya

112

Bir sözlüğü 'AnyObject'e çevirmek benim için en basit çözümdü:

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

bu konsol çıktısıdır

Bunu okumak benim için döküm seçeneğinden daha kolaydır, ancak size toplam anahtar / değer çifti sayısını vermeyeceğini unutmayın.


11
Harika bir yol ve çöplükten çok daha iyi
AbdelHady

109

po çözümü

Konsolda kaçış dizisi olmadan Sözlüğü JSON olarak görmek isteyenler için , işte bunu yapmanın basit bir yolu

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


1
Bir ifade olduğundan ve bir nesne olmadığından, "po" değil "p" olmalıdır. Ancak bu çözüm için çok teşekkürler! Benim için iyi çalışıyor
Alessandro Francucci

@AlessandroFrancucci önemli mi? Komut her iki şekilde de aynı şeyi yapıyor gibi görünüyor.
nickjwallin

Şimdi bunu yapmanın her iki yolu da işe yarıyor. Ama bir "po baskısı" yapmadan önce benim için işe yaramadı. (po, baskı nesnesi anlamına gelir .... daha sonra bir baskı alırsanız ve bir nesne
imho

Harika! PushNotification'dan userInfo'dan hoş bir şekilde yazdırmak için ihtiyacım olan şey
carmen_munich

Bunu bir lldb takma adında kullanmak için bu yorumu kontrol edin , böylece her seferinde yazmak zorunda kalmazsınız!
agirault

36

Fonksiyonel Programlamayı kullanmanın başka bir yolu

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

Çıktı

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

1
Bu en iyi cevap olmalı. Mükemmel çalışıyor!
Yuri Doubov

Veya "daha da işlevsel" olmak için ... dictionary.map {"($ 0): ($ 1)"} .forEach (baskı) (dil-yanak yorumu)
Jon Willis

3
Bu, OP'nin [String: String]sözlüğü için işe yarıyor , ancak [AnyHashable: Any]sözlükler için harika değil , eğer bir değer bir sözlükse, Swift'in hoş olmayan baskısına geri dönüyorsunuz.
Christopher Pickslay

Bu cevabı işaretleyen kitabım var, çünkü hala bu sözdizimini hatırlayamıyorum 🙄
Nitin Alabur

29

Yalnızca hata ayıklama amacıyla, Dizi veya Sözlüğü oldukça basılı bir json'a dönüştürürdüm:

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

Sonra:

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

Konsoldaki sonuç:

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

bLog burada nedir?
Nitesh

@Nitesh bLog, yazdığım, print () ile düzenlenmiş geriye dönük izli basit bir özel kaydedicidir.
Marco M

En güzel çözüm.
Denis Kutlubaev

Projelerinizin her birine bu kod parçacığını eklemekten kaçınmak istiyorsanız, hata ayıklama terminalinde json'u kolayca hesaplamak için bu kodu bir lldb takma adıyla kullanabilirsiniz (ayrıntılar burada ).
agirault

14

Sonuçları bir JSON doğrulayıcısına aktardığınızda sonuç geçersiz olduğu için (genellikle ':' yerine '=' içeren koddan dolayı) burada verilen cevapların çoğunu gerçekten güzel yazdırılmış JSON olarak düşünmüyorum.

Bunu yapmanın bulduğum en kolay yolu, JSON nesnesini, oldukça basılı yazma seçeneğini kullanarak verilere dönüştürmek ve ardından elde edilen verileri kullanarak bir dize yazdırmaktır.

İşte bir örnek:

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

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

Sonuç:

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

DÜZENLEME : OP'nin JSON istemediği belirtildi, ancak veriyi yalnızca yazdırmayı veya konsola aktarmayı öneren yanıtların çok az biçimlendirme sağladığını (varsa) ve bu nedenle de pek yazdırılmadığını gördüm.

OP'nin JSON istememesine rağmen, xcode / swift tarafından konsola gönderilen korkunç formattan çok daha okunabilir bir veri formatı olduğu için uygun bir cevap olduğuna inanıyorum.


1
Teşekkürler, e let jsonData = try! JSONSerialization.data(withJSONObject: response, options: .prettyPrinted);if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
bununla

1
Bu harika! Hata ayıklama terminalinde json'u kolayca hesaplamak için bu kodu bir lldb takma adıyla kullanabilirsiniz (ayrıntılar burada ).
agirault

5

Sadece bir for döngüsü kullanabilir ve her yinelemeyi yazdırabilirsiniz

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

Uzantı uygulaması:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

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

        return self.description
    }
}

Alternatif uygulama:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

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

Kullanım:

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

Çıktı (Xcode 8 beta 2 Playground'da test edilmiştir):

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

1
Sadece bir işlev yerine güzel yazdırmayı bir var yapmanın bir nedeni var mı?
Hayden Holligan

Açıkçası önemli olduğunu sanmıyorum (yanılıyor olabilirim). Ama onu çok kullanırsanız, yazmak daha az olur. Ama ilginç bir soru sorun.
Asdrubal

3
Bir descriptionve debugDescriptionzaten olduğundan, var'ı çağırmak prettyDescriptionve biçimlendirilmiş dizeyi döndürmek daha uygun olabilir .
Toland Hon

5

Swift Sözlüğünü json'a ve geri dönüştürme metodolojisi en temiz olanıdır. Ben Facebook'un kullanmak keski bir sahiptir pjson bir Swift sözlüğü yazdırmak için komutu. Örneğin:

(lldb) pjson dict as NSDictionary

Bu, sözlüğü oldukça yazdırmalı. Bu, daha önce önerilmiş olanı yapmanın çok daha temiz bir yoludur. Not: Şimdilik, dict'i NSDictionary olarak atmanız gerekecek çünkü Objective-C çalışma zamanı Swift sözlüklerini anlamıyor. Bu kısıtlamadan kurtulmak için keski üzerinde zaten bir PR yükselttim.

GÜNCELLEME: Halkla İlişkilerim kabul edildi. Şimdi yukarıda bahsedilen pjson yerine psjson komutunu kullanabilirsiniz .


4

For Swift 3 (& tarafından parlak yanıta bina @Jalakoo ) aşağıdaki yapmak Dictionaryuzantısı:

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

daha sonra bir sözlük yazdırmak herhangi hiyerarşide bir de oldukça (daha iyi bir şekilde dump()bu kullanılarak):

print(dictionary!.prettyPrint)

4

Detaylar

  • Xcode 10.2.1 (10E1001), Swift 5

Çözüm

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

Kullanım

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

Sonuçlar

görüntü açıklamasını buraya girin


2

Buradaki diğer cevabıma göre ayarlandı .

LLDB takma adı kullanan PrettyPrint JSON çözümü

✨ Koda gerek yok

  • Güzel bir json biçimlendirmesi (girintiler, satırsonları, vb.) Elde etmek için, bu komutu lldb terminalinizde ( kaynak ) çalıştırarak bir lldb takma adı tanımlayabilirsiniz :
command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'
  • Muhtemelen XCode'u her açtığınızda diğer adı yeniden tanımlamak istemezsiniz, bu nedenle takma ad tanımını eklemek için aşağıdaki komutu çalıştırın ~/.lldbinit:
echo "command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'" >> ~/.lldbinit
  • Bu, pjsonXCode'daki lldb terminalinizde kullanabileceğiniz takma adı oluşturacaktır:
pjson object

Aşağıdaki Swift nesnesi için çıktıların karşılaştırılması:

// 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"
]

✅ Çıktı pjson dictionary

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

❌ Çıktı 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"
  }
}

❌ Çıktı p (dictionary as! NSDictionary)

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

❌ Çıktı 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"

❌ Çıktı po print(dictionary)

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


1

Hata ayıklarken, Kodlanabilir Protokolü konsola uyan yapının çıktısını
json formatını kullanın.

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 uyumlu CustomDebugStringConvertible

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

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

hata ayıklama yazdırma yapısı

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

1

Data nesnesinden hoş baskı:

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

1
Bu harika! Hata ayıklama terminalinde json'u kolayca hesaplamak için bu kodu bir lldb takma adıyla kullanabilirsiniz (ayrıntılar burada ).
agirault

0

Peki ya:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.