Recherche…


Syntaxe

  • NSJSONSerialization.JSONObjectWithData (jsonData, options: NSJSONReadingOptions) // Renvoie un objet à partir de jsonData. Cette méthode échoue.
  • NSJSONSerialization.dataWithJSONObject (jsonObject, options: NSJSONWritingOptions) // Renvoie NSData à partir d'un objet JSON. Transmettez NSJSONWritingOptions.PrettyPrinted dans les options pour une sortie plus lisible.

Sérialisation JSON, encodage et décodage avec Apple Foundation et la bibliothèque Swift Standard

La classe JSONSerialization est intégrée au framework Foundation d'Apple.

2.2

Lire JSON

La fonction JSONObjectWithData prend NSData et renvoie AnyObject . Vous pouvez utiliser as? pour convertir le résultat à votre type attendu.

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

Vous pouvez passer des options: .AllowFragments au lieu des options: [] pour autoriser la lecture de JSON lorsque l'objet de niveau supérieur n'est pas un tableau ou un dictionnaire.

Ecrire JSON

L'appel de dataWithJSONObject convertit un objet compatible JSON (tableaux imbriqués ou dictionnaires avec des chaînes, des nombres et NSNull ) en NSData brut codé en 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)")
}

Vous pouvez passer des options: .PrettyPrinted au lieu des options: [] pour une jolie impression.

3.0

Même comportement dans Swift 3 mais avec une syntaxe différente.

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

Remarque: La section suivante est actuellement disponible uniquement dans Swift 4.0 et versions ultérieures.

À partir de Swift 4.0, la bibliothèque standard Swift inclut les protocoles Encodable et Decodable pour définir une approche normalisée du codage et du décodage des données. L'adoption de ces protocoles permettra aux implémentations des protocoles Encoder et Decoder prendre vos données et de les encoder ou les décoder depuis et vers une représentation externe telle que JSON. La conformité au protocole Codable combine les protocoles Encodable et Decodable . C'est maintenant le moyen recommandé de gérer JSON dans votre programme.

Encoder et décoder automatiquement

La méthode la plus simple pour rendre un type codable consiste à déclarer ses propriétés comme des types déjà Codable . Ces types incluent les types de bibliothèque standard tels que String , Int et Double ; et les types de Fondation tels que Date , Data et URL . Si les propriétés d'un type sont codables, le type lui-même se conformera automatiquement à Codable en déclarant simplement la conformité.

Prenons l'exemple suivant, dans lequel la structure du Book est conforme à Codable .

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

Notez que les collections standard telles que Array et Dictionary sont conformes à Codable si elles contiennent des types codables.

En adoptant Codable , la structure Book peut maintenant être codée et décodée à partir de JSON en utilisant les classes Apple Foundation JSONEncoder et JSONDecoder , même si Book lui-même ne contient aucun code pour gérer spécifiquement JSON. Les codeurs et décodeurs personnalisés peuvent également être écrits en respectant respectivement les protocoles de Encoder et de Decoder .

Encoder les données 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)

Définissez encoder.outputFormatting = .prettyPrinted pour faciliter la lecture. ## Décoder à partir de données JSON

Décoder à partir de données 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)

Dans l'exemple ci-dessus, Book.self informe le décodeur du type auquel le JSON doit être décodé.

Encodage ou décodage exclusivement

Parfois, vous n'avez peut-être pas besoin de données codables et décodables, par exemple lorsque vous avez uniquement besoin de lire des données JSON à partir d'une API ou que votre programme ne soumet que des données JSON à une API.

Si vous avez l'intention d'écrire uniquement des données JSON, conformez-vous à Encodable .

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

Si vous souhaitez uniquement lire les données JSON, conformez-vous à Decodable .

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

Utilisation de noms de clé personnalisés

Les API utilisent fréquemment des conventions de dénomination autres que le cas camel standard Swift, tel que le cas du serpent. Cela peut devenir un problème quand il s'agit de décoder JSON, car par défaut les clés JSON doivent s'aligner exactement sur les noms de propriété de votre type. Pour gérer ces scénarios, vous pouvez créer des clés personnalisées pour votre type à l'aide du protocole CodingKey .

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

CodingKeys sont générés automatiquement pour les types qui adoptent le protocole Codable , mais en créant notre propre implémentation dans l'exemple ci-dessus, nous Codable notre décodeur à correspondre à la publicationDate cas camel avec le cas de publication_date tel qu'il est fourni par l'API.

SwiftyJSON

SwiftyJSON est un framework Swift conçu pour supprimer le chaînage facultatif dans la sérialisation JSON normale.

Vous pouvez le télécharger ici: https://github.com/SwiftyJSON/SwiftyJSON

Sans SwiftyJSON, votre code ressemblerait à ceci pour trouver le nom du premier livre dans un objet 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
}

Dans SwiftyJSON, ceci est extrêmement simplifié:

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

Cela supprime la nécessité de vérifier chaque champ, car il renverra zéro si l'un d'entre eux est invalide.

Pour utiliser SwiftyJSON, téléchargez la version correcte depuis le dépôt Git - il existe une branche pour Swift 3. Faites simplement glisser le "SwiftyJSON.swift" dans votre projet et importez-le dans votre classe:

import SwiftyJSON

Vous pouvez créer votre objet JSON en utilisant les deux initialiseurs suivants:

let jsonObject = JSON(data: dataObject)

ou

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

Pour accéder à vos données, utilisez les indices:

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

Vous pouvez ensuite analyser votre valeur à un certain type de données, qui renverra une valeur facultative:

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

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

Vous pouvez également compiler vos chemins dans un tableau rapide:

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

Est le même que:

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

SwiftyJSON a également des fonctionnalités pour imprimer ses propres erreurs:

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
}

Si vous devez écrire sur votre objet JSON, vous pouvez utiliser à nouveau les indices:

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

Si vous avez besoin de la chaîne d'origine pour JSON, par exemple si vous devez l'écrire dans un fichier, vous pouvez obtenir la valeur brute:

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

Freddy est une bibliothèque d'analyse JSON gérée par Big Nerd Ranch . Il présente trois avantages principaux:

  1. Type Safety: vous aide à travailler avec l'envoi et la réception de JSON de manière à éviter les pannes à l'exécution.

  2. Idiomatic: profite des génériques, des énumérations et des fonctionnalités de Swift, sans documentation compliquée ni opérateurs personnalisés magiques.

  3. Gestion des erreurs: Fournit des informations d'erreur informatives pour les erreurs JSON courantes.

Exemple de données JSON

Définissons quelques exemples de données JSON à utiliser avec ces exemples.

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

Désérialisation des données brutes

Pour désérialiser les données, nous initialisons un objet JSON puis accédons à une clé particulière.

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

Nous try ici parce que l'accès à json pour la clé "success" pourrait échouer - il pourrait ne pas exister, ou la valeur pourrait ne pas être un booléen.

Nous pouvons également spécifier un chemin d'accès aux éléments imbriqués dans la structure JSON. Le chemin est une liste de clés et d'indices séparés par des virgules qui décrivent le chemin d'accès à une valeur d'intérêt.

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
}

Désérialisation des modèles directement

JSON peut être directement analysé dans une classe de modèle qui implémente le protocole 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
}

Sérialisation des données brutes

Toute valeur JSON peut être sérialisée directement à NSData .

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

Sérialisation de modèles directement

Toute classe de modèle qui implémente le protocole JSONEncodable peut être sérialisée directement dans 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()

Flèche

Arrow est une bibliothèque d'analyse JSON élégante dans Swift.

Il permet d’analyser JSON et de le mapper avec des classes de modèles personnalisées à l’aide d’un opérateur <-- :

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

Exemple:

Modèle rapide

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

Fichier 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"
    }]
}

Cartographie

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

Usage

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

Installation:

Carthage

github "s4cha/Arrow"

CacaoPods

pod 'Arrow'
use_frameworks!

Manuellement

Copiez et collez simplement Arrow.swift dans votre projet Xcode

https://github.com/s4cha/Arrow

Comme cadre

Téléchargez Arrow depuis le référentiel GitHub et créez la cible Framework sur le projet exemple. Puis lien contre ce cadre.

Analyse JSON simple dans des objets personnalisés

Même si les bibliothèques tierces sont bonnes, un moyen simple d’analyser le JSON est fourni par les protocoles. Vous pouvez imaginer que vous avez un objet Todo as

struct Todo {
    let comment: String
}

Chaque fois que vous recevez le JSON, vous pouvez gérer les NSData comme indiqué dans l'autre exemple utilisant l'objet NSJSONSerialization .

Après cela, en utilisant un protocole simple JSONDecodable

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

Et rendre votre structure Todo conforme à JSONDecodable fait le tour

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

Vous pouvez l'essayer avec ce code json:

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

Lorsque vous l'avez obtenu à partir de l'API, vous pouvez le sérialiser comme les exemples précédents présentés dans une occurrence AnyObject . Après cela, vous pouvez vérifier si l'instance est une instance de JSONDictionary

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

L'autre chose à vérifier, spécifique à ce cas car vous avez un tableau de Todo dans le JSON, est le dictionnaire todos

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

Maintenant que vous avez le tableau des dictionnaires, vous pouvez convertir chacun d'entre eux dans un objet Todo en utilisant flatMap (cela supprimera automatiquement les valeurs nil du tableau).

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

JSON Parsing Swift 3

Voici le fichier JSON que nous utiliserons appelé 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?"
    }   ] }

Importez votre fichier JSON dans votre projet

Vous pouvez effectuer cette fonction simple pour imprimer votre fichier 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)
                }
           }
       }
    }

Si vous voulez le placer dans une vue de table, je créerai d'abord un dictionnaire avec un NSObject.

Créez un nouveau fichier swift appelé ParsingObject et créez vos variables de chaîne.

Assurez-vous que le nom de la variable est le même que le fichier JSON

. Par exemple, dans notre projet, nous avons un name et une question . Dans notre nouveau fichier rapide, nous utiliserons

var name: String?
var question: String?

Initialisez le NSObject que nous avons renvoyé dans notre tableau var ViewController.swift = ParsingObject Ensuite, nous effectuerions la même méthode que précédemment avec une modification mineure.

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

Ensuite, nous le montrons dans notre tableview en faisant cela,

    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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow