มีวิธีพิมพ์พจนานุกรม Swift สวย ๆ ลงคอนโซลหรือไม่?


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

พิมพ์สิ่งต่อไปนี้บนคอนโซล:

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

พิมพ์สิ่งต่อไปนี้บนคอนโซล:

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

มีวิธีใดใน Swift ที่จะทำให้พจนานุกรมพิมพ์สวยโดยที่คู่คีย์ - ค่าแต่ละคู่ใช้บรรทัดใหม่


8
คุณสามารถใช้dumpตัวอย่างเช่นหากเป้าหมายคือการตรวจสอบพจนานุกรม stackoverflow.com/documentation/swift/3966/logging-in-swift/…
Eric Aya

14
print(dictionary as! NSDictionary) เคล็ดลับราคาถูก?
BaseZen

ฉันเป็นคำแนะนำการถ่ายโอนข้อมูล () จริงๆเนื่องจากไม่จำเป็นต้องเขียนโค้ดหรือแคสต์ @EricAya ถ้าคุณโพสต์คำตอบพร้อมคำพูดนั้นฉันจะทำเครื่องหมายว่าเป็นคำตอบ
Toland Hon

1
@TolandHon เสร็จแล้ว. ฉันได้คำตอบพร้อมตัวอย่างผลลัพธ์แล้ว
Eric Aya

คำตอบ:


100

คุณสามารถใช้การถ่ายโอนข้อมูลตัวอย่างเช่นหากเป้าหมายคือการตรวจสอบพจนานุกรม dumpเป็นส่วนหนึ่งของไลบรารีมาตรฐานของ Swift

การใช้งาน:

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

dump(dictionary)

เอาท์พุต:

ป้อนคำอธิบายภาพที่นี่


dump พิมพ์เนื้อหาของวัตถุผ่านการสะท้อน (การสะท้อน)

มุมมองโดยละเอียดของอาร์เรย์:

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

พิมพ์:

▿ 4 องค์ประกอบ
- [0]: โจ
- [1]: เจน
- [2]: จิม
- [3]: จอยซ์

สำหรับพจนานุกรม:

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

พิมพ์:

▿ 3 คู่คีย์ / ค่า
▿ [0]: (2 องค์ประกอบ)
- .0: bar
- .1: 33
▿ [1]: (2 องค์ประกอบ)
- .0: baz
- .1: 42
▿ [2]: ( 2 องค์ประกอบ)
- .0: foo
- .1: 10

dumpถูกประกาศเป็นdump(_:name:indent:maxDepth:maxItems:).

พารามิเตอร์แรกไม่มีป้ายกำกับ

มีพารามิเตอร์อื่น ๆ เช่นnameตั้งค่าป้ายกำกับสำหรับวัตถุที่ตรวจสอบ:

dump(attributes, name: "mirroring")

พิมพ์:

▿มิเรอร์: 3 คู่คีย์ / ค่า
▿ [0]: (2 องค์ประกอบ)
- .0: บาร์
- .1: 33
▿ [1]: (2 องค์ประกอบ)
- .0: baz
- .1: 42
▿ [2] : (2 องค์ประกอบ)
- .0: foo
- .1: 10

นอกจากนี้คุณยังสามารถเลือกที่จะพิมพ์เฉพาะจำนวนหนึ่งของรายการที่มีmaxItems:เพื่อแยกวัตถุขึ้นถึงระดับความลึกบางอย่างกับและการเปลี่ยนแปลงการเยื้องของวัตถุที่พิมพ์ด้วยmaxDepth:indent:


7
นี่ไม่ใช่ JSON ที่พิมพ์ออกมาสวย ๆ นี่เป็นเพียงการทิ้งตัวแปร aa ลงในคอนโซล - ไม่ใช่ JSON ที่ถูกต้อง แม้ว่ามันจะเหมาะกับความต้องการของ OP ฉันเชื่อว่าคำถามนั้นต้องการการตอบกลับให้ตรงกับสิ่งนี้
James Wolfe

4
@JamesWolfe This is not pretty printed JSONไม่มีใครว่ามัน OP ถามเกี่ยวกับการพิมพ์พจนานุกรม Swift ที่ค่อนข้างสวย - ไม่มีใครพูดถึง JSON ยกเว้นผู้ตอบนอกประเด็นเพียงไม่กี่คน quesiton ของ OP ไม่เกี่ยวกับ JSON เลย
Eric Aya

@JamesWolfe โปรดอย่าเปลี่ยนคำถาม นั่นจะเป็นความป่าเถื่อน คำถามนั้นชัดเจนเหมือนเดิมและไม่เกี่ยวกับ JSON อย่าเปลี่ยนคำถามเพียงเพราะบางคำตอบพูดถึงสิ่งอื่น ขอบคุณ.
Eric Aya

112

การส่งพจนานุกรมไปที่ 'AnyObject' เป็นวิธีที่ง่ายที่สุดสำหรับฉัน:

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

นี่คือเอาต์พุตคอนโซล

ฉันอ่านง่ายกว่าตัวเลือกการถ่ายโอนข้อมูล แต่โปรดทราบว่าจะไม่ให้จำนวนคีย์ - ค่าทั้งหมด


11
เป็นวิธีที่ยอดเยี่ยมและดีกว่าการถ่ายโอนข้อมูล
AbdelHady

109

วิธีแก้ปัญหา

สำหรับผู้ที่คุณต้องการเห็น Dictionary เป็น JSON โดยไม่มีลำดับการหลีกเลี่ยงในคอนโซลนี่เป็นวิธีง่ายๆในการทำเช่นนั้น

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

อัปเดต

ตรวจสอบคำตอบนี้ด้วยคำตอบ


1
เนื่องจากเป็นนิพจน์ไม่ใช่วัตถุจึงควรเป็น 'p' ไม่ใช่ 'po' แต่ขอบคุณมากสำหรับการแก้ปัญหานี้! ใช้ได้ดีสำหรับฉัน
Alessandro Francucci

@AlessandroFrancucci ไม่สำคัญเหรอ คำสั่งดูเหมือนจะทำสิ่งเดียวกันไม่ว่าจะด้วยวิธีใดก็ตาม
nickjwallin

ตอนนี้ทั้งสองวิธีกำลังทำงานอยู่ แต่ก่อนที่จะทำ "po print" ไม่ได้ผลสำหรับฉัน (po หมายถึงวัตถุพิมพ์ .... ซึ่งค่อนข้างสับสนหากคุณมีการพิมพ์ในภายหลังและไม่ใช่วัตถุ imho)
Alessandro Francucci

สุดยอด! สิ่งที่ฉันต้องการในการพิมพ์ด้วยวิธีที่ดี userInfo จาก PushNotification
carmen_munich

1
ตรวจสอบความคิดเห็นนี้เพื่อใช้ประโยชน์จากสิ่งนี้ในนามแฝง lldb เพื่อที่คุณจะได้ไม่ต้องพิมพ์ทุกครั้ง!
agirault

36

อีกวิธีหนึ่งในการใช้ Functional Programming

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

เอาต์พุต

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

1
นี่น่าจะเป็นคำตอบอันดับต้น ๆ ทำงานได้อย่างสมบูรณ์แบบ!
Yuri Doubov

หรือจะ "ใช้งานได้มากขึ้น" ... dictionary.map {"($ 0): ($ 1)"} .forEach (print) (ความคิดเห็นเกี่ยวกับลิ้น)
Jon Willis

3
สิ่งนี้ใช้ได้กับ[String: String]พจนานุกรมของ OP แต่ไม่เหมาะสำหรับ[AnyHashable: Any]พจนานุกรมหากค่าเป็นพจนานุกรมคุณจะกลับไปใช้การพิมพ์ที่ไม่สวยของ Swift
Christopher Pickslay

ฉันมีหนังสือที่ทำเครื่องหมายคำตอบนี้แล้วเพราะฉันยังจำไวยากรณ์นี้ไม่ได้🙄
Nitin Alabur

29

เพื่อจุดประสงค์ในการดีบักเท่านั้นฉันจะแปลง Array หรือ Dictionary เป็น json ที่พิมพ์ออกมาสวย:

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

จากนั้น:

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

ผลลัพธ์บนคอนโซล:

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

bLog ที่นี่คืออะไร?
Nitesh

@Nitesh bLog เป็นเครื่องมือตัดไม้แบบกำหนดเองง่ายๆพร้อม backtrace ที่ฉันเขียนแก้ไขด้วย print ()
Marco M

ทางออกที่สวยงามที่สุด
Denis Kutlubaev

หากคุณต้องการหลีกเลี่ยงการเพิ่มข้อมูลโค้ดในแต่ละโปรเจ็กต์ของคุณคุณสามารถใช้ประโยชน์จากโค้ดนั้นด้วยนามแฝง lldb เพื่อคำนวณ json ในเทอร์มินัลดีบักได้อย่างง่ายดาย (ดูรายละเอียดที่นี่ )
agirault

14

ฉันจะไม่พิจารณาคำตอบมากมายที่ให้ไว้ที่นี่ JSON ที่พิมพ์ออกมาสวยจริงเนื่องจากเมื่อคุณส่งผลลัพธ์ไปยังเครื่องมือตรวจสอบ JSON ผลลัพธ์จะไม่ถูกต้อง (มักเกิดจากรหัสรวมถึง '=' แทนที่จะเป็น ':')

วิธีที่ง่ายที่สุดที่ฉันพบในการทำเช่นนี้คือการแปลงออบเจ็กต์ JSON เป็นข้อมูลโดยใช้ตัวเลือกการเขียนแบบสวย ๆ จากนั้นพิมพ์สตริงโดยใช้ข้อมูลผลลัพธ์

นี่คือตัวอย่าง:

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

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

ผลลัพธ์:

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

แก้ไข : มีการชี้ให้เห็นว่า OP ไม่ได้ขอ JSON แต่ฉันพบว่าคำตอบที่แนะนำให้พิมพ์หรือทิ้งข้อมูลลงในคอนโซลนั้นให้การจัดรูปแบบน้อยมาก (ถ้ามี) และจึงพิมพ์ได้ไม่สวย

ฉันเชื่อว่าแม้ว่า OP จะไม่ขอ JSON แต่ก็เป็นคำตอบที่ใช้ได้เนื่องจากเป็นรูปแบบข้อมูลที่อ่านได้ง่ายกว่ารูปแบบที่น่ากลัวที่พ่นออกมาในคอนโซลโดย xcode / swift


1
ขอบคุณด้วยเหตุนี้ฉันจึงสามารถพิมพ์ได้สวยท่ามกลางการดีบักผ่าน e let jsonData = try! JSONSerialization.data(withJSONObject: response, options: .prettyPrinted);if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
BangOperator

1
นี่มันเยี่ยมมาก! คุณสามารถใช้ประโยชน์จากรหัสนี้ด้วยนามแฝง lldb เพื่อคำนวณ json ในเทอร์มินัลดีบักได้อย่างง่ายดาย (ดูรายละเอียดที่นี่ )
agirault

5

คุณสามารถใช้สำหรับการวนซ้ำและพิมพ์การวนซ้ำแต่ละครั้ง

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

แอปพลิเคชันในส่วนขยาย:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

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

        return self.description
    }
}

แอปพลิเคชันอื่น:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

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

การใช้งาน:

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

เอาต์พุต (ทดสอบใน Xcode 8 beta 2 Playground):

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

1
มีเหตุผลไหมที่คุณสร้าง prettyprint เป็น var แทนที่จะเป็นฟังก์ชัน?
Hayden Holligan

จริงๆแล้วฉันไม่คิดว่ามันสำคัญ (ฉันอาจจะผิด) แต่ถ้าคุณใช้มากก็พิมพ์น้อยลง แต่ให้ตั้งคำถามที่น่าสนใจ
Asdrubal

3
ตั้งแต่มีdescriptionและdebugDescriptionแล้วก็อาจจะมีความเหมาะสมมากขึ้นที่จะเรียกวาprettyDescriptionและกลับสตริงที่จัดรูปแบบ
Toland Hon

5

วิธีการในการแปลง Swift Dictionary เป็น json และ back เป็นวิธีที่เรียบง่ายที่สุด ฉันใช้สิ่วของ Facebook ซึ่งมีคำสั่งpjsonเพื่อพิมพ์พจนานุกรม Swift เช่น:

(lldb) pjson dict as NSDictionary

นี่น่าจะพิมพ์พจนานุกรมได้สวย นี่เป็นวิธีที่สะอาดกว่ามากในการทำสิ่งที่แนะนำไปแล้ว ป.ล. ในตอนนี้คุณจะต้องใช้ dict เป็น NSDictionary เนื่องจากรันไทม์ Objective-C ไม่เข้าใจพจนานุกรม Swift ฉันได้ทำการประชาสัมพันธ์เกี่ยวกับสิ่วเพื่อกำจัดข้อ จำกัด นั้นแล้ว

UPDATE: PR ของฉันได้รับการยอมรับ ตอนนี้คุณสามารถใช้คำสั่งpsjsonแทนpjson ที่กล่าวมาข้างต้น


4

สำหรับSwift 3 (& สร้างคำตอบที่ยอดเยี่ยมโดย@Jalakoo ) ให้สร้างDictionaryส่วนขยายต่อไปนี้:

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

แล้วพิมพ์พจนานุกรมของลำดับชั้นใด ๆในสวยวิธี (ดีกว่าdump()) โดยใช้นี้

print(dictionary!.prettyPrint)

4

รายละเอียด

  • Xcode 10.2.1 (10E1001), Swift 5

วิธีการแก้

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

การใช้งาน

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

ผล

ป้อนคำอธิบายภาพที่นี่


3

ปรับขึ้นอยู่กับคำตอบอื่น ๆ ของฉันที่นี่

โซลูชัน PrettyPrint JSON โดยใช้นามแฝง LLDB

ไม่ต้องใช้รหัส

  • ในการจัดรูปแบบ json ที่ดี (การเยื้องขึ้นบรรทัดใหม่ ฯลฯ ) คุณสามารถกำหนดนามแฝง lldb โดยรันคำสั่งนี้ในเทอร์มินัล lldb ของคุณ (ที่มา ):
command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'
  • คุณอาจไม่ต้องการกำหนดนามแฝงใหม่ทุกครั้งที่คุณเปิด XCode ดังนั้นให้รันคำสั่งต่อไปนี้เพื่อต่อท้ายนิยามนามแฝงกับ~/.lldbinit:
echo "command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'" >> ~/.lldbinit
  • สิ่งนี้จะสร้างpjsonนามแฝงที่คุณสามารถใช้ในเทอร์มินัล lldb ของคุณใน XCode:
pjson object

การเปรียบเทียบผลลัพธ์สำหรับวัตถุ Swift ต่อไปนี้:

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

✅ผลลัพธ์ของ pjson dictionary

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

❌ผลลัพธ์ของ 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"
  }
}

❌ผลลัพธ์ของ p (dictionary as! NSDictionary)

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

❌ผลลัพธ์ของ 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"

❌ผลลัพธ์ของ po print(dictionary)

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


1

เมื่อทำการดีบักเอาต์พุตโครงสร้างที่เป็นไปตาม Codable Protocol ไปยังคอนโซล
โดยใช้รูปแบบ 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 สอดคล้องกับ CustomDebugStringConvertible

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

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

โครงสร้างการพิมพ์แก้จุดบกพร่อง

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

1

พิมพ์สวยจากวัตถุข้อมูล:

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

1
นี่มันเยี่ยมมาก! คุณสามารถใช้ประโยชน์จากรหัสนี้ด้วยนามแฝง lldb เพื่อคำนวณ json ในเทอร์มินัลดีบักได้อย่างง่ายดาย (ดูรายละเอียดที่นี่ )
agirault

0

เกี่ยวกับ:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.