Поиск…


Синтаксис

  • NSJSONSerialization.JSONObjectWithData (jsonData, options: NSJSONReadingOptions) // Возвращает объект из jsonData. Этот метод бросает неудачу.
  • NSJSONSerialization.dataWithJSONObject (jsonObject, options: NSJSONWritingOptions) // Возвращает NSData из объекта JSON. Перейдите в NSJSONWritingOptions.PrettyPrinted в опции для вывода, который более читабельен.

Сериализация JSON, кодирование и декодирование с помощью Apple Foundation и стандартной библиотеки Swift

Класс JSONSerialization встроен в структуру Apple Foundation.

2,2

Читать JSON

Функция JSONObjectWithData принимает NSData и возвращает AnyObject . Вы можете использовать as? для преобразования результата в ожидаемый тип.

do {
    guard let jsonData = "[\"Hello\", \"JSON\"]".dataUsingEncoding(NSUTF8StringEncoding) else {
        fatalError("couldn't encode string as UTF-8")
    }

    // Convert JSON from NSData to AnyObject
    let jsonObject = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
    
    // Try to convert AnyObject to array of strings
    if let stringArray = jsonObject as? [String] {
        print("Got array of strings: \(stringArray.joinWithSeparator(", "))")
    }
} catch {
    print("error reading JSON: \(error)")
}

Вы можете передавать options: .AllowFragments вместо options: [] чтобы разрешить чтение JSON, когда объект верхнего уровня не является массивом или словарем.

Написать JSON

Вызов dataWithJSONObject преобразует JSON-совместимый объект (вложенные массивы или словари со строками, номерами и NSNull ) в необработанные NSData закодированные как UTF-8.

do {
    // Convert object to JSON as NSData
    let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonObject, options: [])
    print("JSON data: \(jsonData)")
    
    // Convert NSData to String
    let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)!
    print("JSON string: \(jsonString)")
} catch {
    print("error writing JSON: \(error)")
}

Вы можете передать options: .PrettyPrinted вместо options: [] для довольно-печатной.

3.0

Такое же поведение в Swift 3, но с другим синтаксисом.

do {
    guard let jsonData = "[\"Hello\", \"JSON\"]".data(using: String.Encoding.utf8) else {
        fatalError("couldn't encode string as UTF-8")
    }
    
    // Convert JSON from NSData to AnyObject
    let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
    
    // Try to convert AnyObject to array of strings
    if let stringArray = jsonObject as? [String] {
        print("Got array of strings: \(stringArray.joined(separator: ", "))")
    }
} catch {
    print("error reading JSON: \(error)")
}

do {
    // Convert object to JSON as NSData
    let jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
    print("JSON data: \(jsonData)")

    // Convert NSData to String
    let jsonString = String(data: jsonData, encoding: .utf8)!
    print("JSON string: \(jsonString)")
} catch {
    print("error writing JSON: \(error)")
}

Примечание. В настоящее время следующие доступны только в Swift 4.0 и более поздних версиях.

Начиная с Swift 4.0, стандартная библиотека Swift включает в себя протоколы Encodable и Decodable для определения стандартизованного подхода к кодированию и декодированию данных. Принятие этих протоколов позволит реализации протоколов Encoder и Decoder принимать ваши данные и кодировать или декодировать их в и из внешнего представления, такого как JSON. Соответствие с Codable протоколом сочетает в Encodable и Decodable протоколы. Это теперь рекомендуемое средство для обработки JSON в вашей программе.

Автоматическое кодирование и декодирование

Самый простой способ сделать тип codable - объявить его свойства как типы, которые уже являются Codable . Эти типы включают стандартные типы библиотек, такие как String , Int и Double ; и типы Foundation, такие как Date , Data и URL . Если свойства типа можно кодировать, сам тип автоматически будет соответствовать Codable простым объявлением соответствия.

Рассмотрим следующий пример, в котором структура Book соответствует Codable .

struct Book: Codable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Обратите внимание, что стандартные коллекции, такие как Array и Dictionary соответствуют Codable если они содержат типы codable.

Приняв Codable , структура Book теперь может быть закодирована и декодирована из JSON с использованием классов Apple Foundation JSONEncoder и JSONDecoder , хотя сама Book не содержит кода для специфической обработки JSON. Пользовательские кодировщики и декодеры также могут быть записаны, соответственно, в соответствии с протоколами Encoder и Decoder .

Кодировать данные JSON

// Create an instance of Book called book
let encoder = JSONEncoder()
let data = try! encoder.encode(book) // Do not use try! in production code
print(data)

Установите encoder.outputFormatting = .prettyPrinted для упрощения чтения. ## Декодирование данных JSON

Декодирование данных JSON

// Retrieve JSON string from some source
let jsonData = jsonString.data(encoding: .utf8)!
let decoder = JSONDecoder()
let book = try! decoder.decode(Book.self, for: jsonData) // Do not use try! in production code
print(book)

В приведенном выше примере Book.self сообщает декодеру того типа, который должен быть декодирован JSON.

Кодирование или декодирование Исключительно

Иногда вам могут не потребоваться кодирование и декодирование данных, например, когда вам нужно только считывать данные JSON из API или если ваша программа только передает данные JSON в API.

Если вы собираетесь писать только данные JSON, совместите свой тип с Encodable .

struct Book: Encodable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Если вы собираетесь читать только данные JSON, совместите свой тип с Decodable .

struct Book: Decodable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Использование пользовательских имен ключей

API часто используют соглашения об именах, отличные от случая верблюжьего верблюда, такого как случай с змеей. Это может стать проблемой, когда дело доходит до декодирования JSON, поскольку по умолчанию ключи JSON должны точно совпадать с именами свойств вашего типа. Чтобы справиться с этими сценариями, вы можете создавать собственные ключи для своего типа, используя протокол CodingKey .

struct Book: Codable {
    // ...
    enum CodingKeys: String, CodingKey { 
        case title
        case authors
        case publicationDate = "publication_date"
    }
}

CodingKeys генерируются автоматически для типов , которые принимают в Codable протокола, но путем создания нашей собственной реализации в приведенном выше примере , мы позволяем нашим декодером , чтобы соответствовать местному верблюд случай publicationDate с змея случае publication_date , как они поступают по API.

SwiftyJSON

SwiftyJSON - это структура Swift, созданная для устранения необходимости дополнительной привязки в обычной сериализации JSON.

Вы можете скачать его здесь: https://github.com/SwiftyJSON/SwiftyJSON

Без SwiftyJSON ваш код будет выглядеть так, чтобы найти имя первой книги в объекте JSON:

if let jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [[String: AnyObject]],
let bookName = (jsonObject[0]["book"] as? [String: AnyObject])?["name"] as? String {
    //We can now use the book name
}

В SwiftyJSON это очень упрощено:

let json = JSON(data: data)
if let bookName = json[0]["book"]["name"].string {
    //We can now use the book name
}

Это устраняет необходимость проверять каждое поле, так как оно возвращает нуль, если какой-либо из них недействителен.

Чтобы использовать SwiftyJSON, загрузите правильную версию из репозитория Git - есть ветка для Swift 3. Просто перетащите «SwiftyJSON.swift» в свой проект и импортируйте в свой класс:

import SwiftyJSON

Вы можете создать свой объект JSON, используя следующие два инициализатора:

let jsonObject = JSON(data: dataObject)

или же

let jsonObject = JSON(jsonObject) //This could be a string in a JSON format for example

Чтобы получить доступ к своим данным, используйте индексы:

let firstObjectInAnArray = jsonObject[0]
let nameOfFirstObject = jsonObject[0]["name"]

Затем вы можете проанализировать свое значение на определенный тип данных, который вернет необязательное значение:

let nameOfFirstObject = jsonObject[0]["name"].string //This will return the name as a string

let nameOfFirstObject = jsonObject[0]["name"].double //This will return null

Вы также можете скомпилировать свои пути в быстрый массив:

let convolutedPath = jsonObject[0]["name"][2]["lastName"]["firstLetter"].string

Такой же как:

let convolutedPath = jsonObject[0, "name", 2, "lastName", "firstLetter"].string

SwiftyJSON также имеет функциональность для печати собственных ошибок:

if let name = json[1337].string {
    //You can use the value - it is valid
} else {
    print(json[1337].error) // "Array[1337] is out of bounds" - You cant use the value
}

Если вам нужно написать свой объект JSON, вы можете снова использовать индексы:

var originalJSON:JSON = ["name": "Jack", "age": 18]
originalJSON["age"] = 25 //This changes the age to 25
originalJSON["surname"] = "Smith" //This creates a new field called "surname" and adds the value to it

Если вам нужна оригинальная строка для JSON, например, если вам нужно записать ее в файл, вы можете получить исходное значение:

if let string = json.rawString() { //This is a String object
    //Write the string to a file if you like
}

if let data = json.rawData() { //This is an NSData object
    //Send the data to your server if you like
}

Фредди

Freddy - это библиотека разбора JSON, которую ведет Big Nerd Ranch . Он имеет три основных преимущества:

  1. Тип Безопасность: Помогает вам работать с отправкой и получением JSON таким образом, чтобы предотвратить сбои во время выполнения.

  2. Idiomatic: использует преимущества генераторов Swift, перечислений и функциональных возможностей без сложной документации или магических пользовательских операторов.

  3. Обработка ошибок. Предоставляет информативную информацию об ошибках для часто встречающихся ошибок JSON.

Пример данных JSON

Давайте определим некоторые примеры данных JSON для использования с этими примерами.

{
  "success": true,
  "people": [
    {
      "name": "Matt Mathias",
      "age": 32,
      "spouse": true
    },
    {
      "name": "Sergeant Pepper",
      "age": 25,
      "spouse": false
    }
  ],
  "jobs": [
    "teacher",
    "judge"
  ],
  "states": {
    "Georgia": [
      30301,
      30302,
      30303
    ],
    "Wisconsin": [
      53000,
      53001
    ]
  }
}
let jsonString = "{\"success\": true, \"people\": [{\"name\": \"Matt Mathias\",\"age\": 32,\"spouse\": true},{\"name\": \"Sergeant Pepper\",\"age\": 25,\"spouse\": false}],\"jobs\": [\"teacher\",\"judge\"],\"states\": {\"Georgia\": [30301,30302,30303],\"Wisconsin\": [53000,53001]}}"
let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!

Удаление десериализации исходных данных

Чтобы десериализовать данные, мы инициализируем объект JSON затем обращаемся к определенному ключу.

do {
    let json = try JSON(data: jsonData)
    let success = try json.bool("success")
} catch {
    // do something with the error
}

Мы try здесь, потому что доступ к json для ключевого "success" может быть неудачным - он может не существовать, или значение может быть не логическим.

Мы также можем указать путь доступа к элементам, вложенным в структуру JSON. Путь представляет собой список ключей и индексов, разделенных запятыми, которые описывают путь к интересующей стоимости.

do {
    let json = try JSON(data: jsonData)
    let georgiaZipCodes = try json.array("states", "Georgia")
    let firstPersonName = try json.string("people", 0, "name")
} catch {
    // do something with the error
}

Десериализация моделей напрямую

JSON может быть непосредственно разобран на класс модели, который реализует протокол JSONDecodable .

public struct Person {
    public let name: String
    public let age: Int
    public let spouse: Bool
}

extension Person: JSONDecodable {
    public init(json: JSON) throws {
        name = try json.string("name")
        age = try json.int("age")
        spouse = try json.bool("spouse")
    }
}

do {
    let json = try JSON(data: jsonData)
    let people = try json.arrayOf("people", type: Person.self)
} catch {
    // do something with the error
}

Сериализация исходных данных

Любое значение JSON может быть сериализовано непосредственно в NSData .

let success = JSON.Bool(false)
let data: NSData = try success.serialize()

Сериализация моделей напрямую

Любой класс модели, реализующий протокол JSONEncodable , может быть сериализован непосредственно в NSData .

extension Person: JSONEncodable {
    public func toJSON() -> JSON {
        return .Dictionary([
            "name": .String(name),
            "age": .Int(age),
            "spouse": .Bool(spouse)
        ])
    }
}

let newPerson = Person(name: "Glenn", age: 23, spouse: true)
let data: NSData = try newPerson.toJSON().serialize()

Стрела

Arrow - это элегантная библиотека разбора JSON в Swift.

Он позволяет анализировать JSON и сопоставлять его с пользовательскими классами моделей с помощью оператора <-- :

identifier <-- json["id"]
name <-- json["name"]
stats <-- json["stats"]

Пример:

Модель Swift

struct Profile {
    var identifier = 0
    var name = ""
    var link: NSURL?
    var weekday: WeekDay = .Monday
    var stats = Stats()
    var phoneNumbers = [PhoneNumber]()
}

Файл JSON

{
    "id": 15678,
    "name": "John Doe",
    "link": "https://apple.com/steve",
    "weekdayInt" : 3,
    "stats": {
        "numberOfFriends": 163,
        "numberOfFans": 10987
    },
    "phoneNumbers": [{
                     "label": "house",
                     "number": "9809876545"
                     }, {
                     "label": "cell",
                     "number": "0908070656"
                     }, {
                     "label": "work",
                     "number": "0916570656"
    }]
}

картографирование

extension Profile: ArrowParsable {
    mutating func deserialize(json: JSON) {
        identifier <-- json["id"]
        link <-- json["link"]
        name <-- json["name"]
        weekday <-- json["weekdayInt"]
        stats <- json["stats"]
        phoneNumbers <-- json["phoneNumbers"]
    }
}

использование

let profile = Profile()
profile.deserialize(json)

Монтаж:

Карфаген

github "s4cha/Arrow"

CocoaPods

pod 'Arrow'
use_frameworks!

Вручную

Просто скопируйте и вставьте Arrow.swift в свой проект Xcode

https://github.com/s4cha/Arrow

Как A Framework

Загрузите Arrow из репозитория GitHub и создайте целевой объект Framework в примере проекта. Затем ссылку на эту структуру.

Простой JSON-анализ в пользовательских объектах

Даже если сторонние библиотеки хороши, простой способ разобрать JSON обеспечивается протоколами. Вы можете себе представить, что у вас есть объект Todo as

struct Todo {
    let comment: String
}

Всякий раз, когда вы получаете JSON, вы можете обрабатывать простые NSData как показано в другом примере, используя объект NSJSONSerialization .

После этого, используя простой протокол JSONDecodable

typealias JSONDictionary = [String:AnyObject]
protocol JSONDecodable {
    associatedtype Element
    static func from(json json: JSONDictionary) -> Element?
}

И превращение вашей структуры Todo соответствие с JSONDecodable делает трюк

extension Todo: JSONDecodable {
    static func from(json json: JSONDictionary) -> Todo? {
        guard let comment = json["comment"] as? String else { return nil }
        return Todo(comment: comment)
    }
}

Вы можете попробовать это с помощью json-кода:

{
    "todos": [
        {
            "comment" : "The todo comment"
        }
    ]
}

Когда вы получили его из API, вы можете сериализовать его как предыдущие примеры, показанные в экземпляре AnyObject . После этого вы можете проверить, является ли экземпляр экземпляром JSONDictionary

guard let jsonDictionary = dictionary as? JSONDictionary else { return }

Другое дело, чтобы проверить, конкретный для этого случая, потому что у вас есть массив Todo в JSON, это словарь todos

guard let todosDictionary = jsonDictionary["todos"] as? [JSONDictionary] else { return }

Теперь, когда вы получили массив словарей, вы можете преобразовать каждый из них в объект Todo с помощью flatMap (он автоматически удалит значения nil из массива)

let todos: [Todo] = todosDictionary.flatMap { Todo.from(json: $0) }

JSON Parsing Swift 3

Вот файл JSON, который мы будем использовать под названием animals.json

{
    "Sea Animals": [
    {
     "name": "Fish",
     "question": "How many species of fish are there?"    },
                {
                "name": "Sharks",
                "question": "How long do sharks live?"
                },
                {
                "name": "Squid",
                "question": "Do squids have brains?"
                },
                {
                "name": "Octopus",
                "question": "How big do octopus get?"
                },
                {
                "name": "Star Fish",
                "question": "How long do star fish live?"
                }
                ],
    "mammals": [
                {
      "name": "Dog",
      "question": "How long do dogs live?"
    },
    {
      "name": "Elephant",
      "question": "How much do baby elephants weigh?"
    },
    {
      "name": "Cats",
      "question": "Do cats really have 9 lives?"
    },
    {
      "name": "Tigers",
      "question": "Where do tigers live?"
    },
    {
      "name": "Pandas",
      "question": "WHat do pandas eat?"
    }   ] }

Импортируйте свой JSON-файл в свой проект

Вы можете выполнить эту простую функцию, чтобы распечатать свой файл JSON

   func jsonParsingMethod() {
        //get the file
        let filePath = Bundle.main.path(forResource: "animals", ofType: "json")
        let content = try! String(contentsOfFile: filePath!)
        
        let data: Data = content.data(using: String.Encoding.utf8)!
        let json: NSDictionary =  try! JSONSerialization.jsonObject(with: data as Data, options:.mutableContainers) as! NSDictionary
      
//Call which part of the file you'd like to pare
        if let results = json["mammals"] as? [[String: AnyObject]] {
            
            for res in results {
                //this will print out the names of the mammals from out file.
                if let rates = res["name"] as? String {
                    print(rates)
                }
           }
       }
    }

Если вы хотите поместить его в табличное представление, я бы сначала создал словарь с NSObject.

Создайте новый быстрый файл под названием ParsingObject и создайте строковые переменные.

Убедитесь, что имя переменной совпадает с именем файла JSON

, Например, в нашем проекте у нас есть name и question поэтому в нашем новом быстром файле мы будем использовать

var name: String?
var question: String?

Инициализируйте NSObject, который мы вернули в наш ViewController.swift var array = ParsingObject. Затем мы выполнили тот же самый метод, который мы имели раньше, с незначительной модификацией.

     func jsonParsingMethod() {
            //get the file
            let filePath = Bundle.main.path(forResource: "animals", ofType: "json")
            let content = try! String(contentsOfFile: filePath!)
            
            let data: Data = content.data(using: String.Encoding.utf8)!
            let json: NSDictionary =  try! JSONSerialization.jsonObject(with: data as Data, options:.mutableContainers) as! NSDictionary
            
//This time let's get Sea Animals
            let results = json["Sea Animals"] as? [[String: AnyObject]]
            
//Get all the stuff using a for-loop
            for i in 0 ..< results!.count {
                
//get the value
                let dict = results?[i]
                let resultsArray = ParsingObject()
                
//append the value to our NSObject file
                resultsArray.setValuesForKeys(dict!)
                array.append(resultsArray)
                
            }
          
        }

Затем мы показываем это в нашем столе, делая это,

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return array.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//This is where our values are stored
            let object = array[indexPath.row]
            cell.textLabel?.text = object.name
            cell.detailTextLabel?.text = object.question
            return cell
        }


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow