Чи є спосіб гарненько надрукувати словники 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 спосіб дістати його до симпатичних словників друку, де кожна пара ключ-значення займає новий рядок?


7
Ви можете використати dump, наприклад, якщо метою є перевірка словника. stackoverflow.com/documentation/swift/3966/logging-in-swift/…
Ерік Ая

13
print(dictionary as! NSDictionary) дешевий фокус?
BaseZen

Я дійсно пропоную дамп (), оскільки для цього не потрібно писати будь-який код чи кидати його. @EricAya, якщо ви опублікуєте відповідь із цим зауваженням, я позначу це як відповідь.
Toland Hon

1
@TolandHon Готово. Я відповів на прикладі результату.
Eric Aya,

Відповіді:


99

Наприклад, ви можете використовувати дамп , якщо метою є перевірка словника. dumpє частиною стандартної бібліотеки Свіфта.

Використання:

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: бар
- .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:.


5
Це не досить друкований JSON, це просто скидання змінної в консоль - недійсний JSON. Хоча це відповідає потребам OP, я вважаю, що питання потребує переформулювання, щоб відповідати цьому.
Джеймс Вульф,

4
@JamesWolfe This is not pretty printed JSONНіхто не казав, що це було. OP запитав про симпатичний друк словників Swift - ніхто не говорить про JSON, окрім кількох невідповідачів. Запитання ОП взагалі не стосується JSON.
Ерік Ая,

@JamesWolfe Також, будь ласка, не змінюйте питання. Це було б вандалізмом. Питання ясне, як воно є, і справа не в JSON. Не змінюйте питання лише тому, що деякі відповіді говорять про щось інше. Дякую.
Ерік Ая,

112

Передача словника в "AnyObject" для мене було найпростішим рішенням:

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

це вихід консолі

Мені це легше прочитати, ніж варіант дампа, але зауважте, що загальна кількість ключів-значень не дасть вам.


11
Це блискучий спосіб і спосіб кращий за звалище
АбдельХаді

109

po рішення

Для тих, хто хоче бачити словник як JSON без вихідної послідовності в консолі , ось простий спосіб це зробити

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


1
Оскільки це вираз, а не об'єкт, він повинен бути "p", а не "po". Але велике спасибі за це рішення! Для мене чудово працює
Алессандро Франкуччі

@AlessandroFrancucci це має значення? Здається, команда робить те саме в будь-якому випадку.
nickjwallin

Тепер обидва способи це працюють. Але до того, як робити "друк", мені це не працювало. (po означає об’єкт друку .... що трохи заплутано, якщо згодом у вас є друк, а не об’єкт imho)
Алессандро Франкуччі

Чудово! саме те, що мені потрібно було надрукувати гарним способом userInfo з PushNotification
carmen_munich

Перевірте цей коментар, щоб використати його в псевдонімі lldb, щоб вам не потрібно було його вводити щоразу!
agirault

36

Ще один спосіб використання функціонального програмування

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

Вихідні дані

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

1
Це має бути головною відповіддю. Працює ідеально!
Юрій Дубов

Або бути "ще більш функціональним" ... dictionary.map {"($ 0): ($ 1)"}. ForEach (print) (коментар на вустах)
Джон Вілліс,

3
Це працює для [String: String]словника OP , але це не чудово для [AnyHashable: Any]словників, де якщо значення є словником, ви повернулися до неприємного друку Swift.
Крістофер Пікслей

Я відповів на книгу цією відповіддю🙂, оскільки досі не пам’ятаю цей синтаксис 🙄
Нітін Алабур,

29

Тільки для налагодження я б перетворив масив або словник на досить надрукований 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 bLog - це простий користувацький реєстратор із зворотним відстеженням, який я написав, відредагований за допомогою print ().
Marco M

Найкрасивіше рішення.
Денис Кутлубаєв

Якщо ви хочете уникнути додавання цього фрагмента коду до кожного з ваших проектів, ви можете використати цей код із псевдонімом 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"
    }
}

РЕДАГУВАТИ : було зазначено, що ОП не просив 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 і надрукувати кожну ітерацію

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
Чи є причина, чому ви зробили досить друк var, а не просто функцію?
Хайден Холліган,

Чесно кажучи, я не думаю, що це має значення (я можу помилитися). Але якщо ви використовуєте його багато, тоді менше вводити текст. Але підніміть цікаве питання.
Asdrubal

3
Оскільки існує a descriptionі debugDescriptionвже, можливо, було б доцільніше викликати var prettyDescriptionі повернути відформатований рядок.
Toland Hon

5

Методика перетворення Swift Dictionary в json і назад є найоптимальнішою. Я використовую долото Facebook, яке має команду pjson, щоб надрукувати словник Swift. Наприклад:

(lldb) pjson dict as NSDictionary

Це має досить роздрукувати словник. Це набагато чистіший спосіб зробити те, що вже було запропоновано. PS На даний момент вам доведеться кидати dict як NSD Dictionary, оскільки середовище виконання Objective-C не розуміє словників Swift. Я вже підняв PR на зубилі, щоб позбутися цього обмеження.

ОНОВЛЕННЯ: Мій 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")

Результати

введіть тут опис зображення


2

Коригується на основі моєї іншої відповіді тут .

Рішення 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, на консолі у
форматі 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.