Zoeken…


Syntaxis

  • NSJSONSerialization.JSONObjectWithData (jsonData, opties: NSJSONReadingOptions) // Retourneert een object van jsonData. Deze methode veroorzaakt falen.
  • NSJSONSerialization.dataWithJSONObject (jsonObject, opties: NSJSONWritingOptions) // Retourneert NSData van een JSON-object. Geef NSJSONWritingOptions.Pretty door Afgedrukt in opties voor een uitvoer die beter leesbaar is.

JSON Serialisatie, codering en decodering met Apple Foundation en de Swift Standard Library

De JSONSerialization- klasse is ingebouwd in het framework van Apple.

2.2

Lees JSON

De JSONObjectWithData functie gebruikt NSData en retourneert AnyObject . U kunt gebruiken as? om het resultaat naar uw verwachte type te converteren.

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

U kunt options: .AllowFragments doorgeven options: .AllowFragments plaats van options: [] om het lezen van JSON toe te staan wanneer het object op het hoogste niveau geen matrix of woordenboek is.

Schrijf JSON

Door dataWithJSONObject roepen, dataWithJSONObject een JSON-compatibel object (geneste arrays of woordenboeken met tekenreeksen, nummers en NSNull ) NSNull naar onbewerkte NSData gecodeerd als 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)")
}

U kunt options: .PrettyPrinted doorgeven options: .PrettyPrinted plaats van options: [] voor mooie afdrukken.

3.0

Hetzelfde gedrag in Swift 3 maar met een andere syntaxis.

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

Opmerking: het volgende is momenteel alleen beschikbaar in Swift 4.0 en hoger.

Vanaf Swift 4.0 bevat de Swift-standaardbibliotheek de protocollen Encodable en Decodable om een gestandaardiseerde benadering van gegevenscodering en decodering te definiëren. Als u deze protocollen toepast, kunnen implementaties van de Encoder en Decoder uw gegevens verwerken en coderen of decoderen van en naar een externe weergave zoals JSON. Conformiteit met het Codable protocol combineert zowel de Encodable als de Decodable protocollen. Dit is nu het aanbevolen middel om JSON in uw programma te verwerken.

Automatisch coderen en decoderen

De eenvoudigste manier om een type codeerbaar te maken, is door de eigenschappen ervan aan te geven als typen die al Codable . Deze typen omvatten standaardbibliotheektypen zoals String , Int en Double ; en Funderingstypes zoals Date , Data en URL . Als de eigenschappen van een type Codable zijn, zal het type zelf automatisch voldoen aan Codable door eenvoudig de conformiteit aan te geven.

Neem het volgende voorbeeld, waarin het Book structuur voldoet aan Codable .

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

Merk op dat standaardcollecties zoals Array en Dictionary voldoen aan Codable als ze Codable types bevatten.

Door het aannemen van Codable , het Book kunnen structuur nu worden gecodeerd en gedecodeerd uit JSON met behulp van de Stichting Apple klassen JSONEncoder en JSONDecoder , hoewel Book zelf bevat geen code om specifiek te behandelen JSON. Aangepaste encoders en decoders kunnen ook worden geschreven door respectievelijk te voldoen aan de Encoder en Decoder .

Codeer naar JSON-gegevens

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

Set encoder.outputFormatting = .prettyPrinted voor gemakkelijker lezen. ## Decoderen van JSON-gegevens

Decoderen van JSON-gegevens

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

In het bovenstaande voorbeeld informeert Book.self de decoder van het type waarnaar de JSON moet worden gedecodeerd.

Exclusief coderen of decoderen

Soms hebt u mogelijk geen gegevens nodig die zowel codeerbaar als decodeerbaar zijn, zoals wanneer u alleen JSON-gegevens van een API hoeft te lezen of als uw programma alleen JSON-gegevens naar een API verzendt.

Als u alleen JSON-gegevens wilt schrijven, moet u uw type conformeren aan Encodable .

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

Als u alleen JSON-gegevens wilt lezen, moet u uw type aanpassen aan Decodable .

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

Aangepaste sleutelnamen gebruiken

API's maken vaak gebruik van andere naamgevingsconventies dan de Swift-standaard kamelenhouder, zoals een slangenhouder. Dit kan een probleem worden als het gaat om het decoderen van JSON, omdat de JSON-sleutels standaard exact moeten overeenkomen met de eigenschapsnamen van uw type. Om deze scenario's te verwerken, kunt u aangepaste sleutels voor uw type maken met behulp van het CodingKey protocol.

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

CodingKeys worden automatisch gegenereerd voor typen die het Codable protocol gebruiken, maar door onze eigen implementatie in het bovenstaande voorbeeld te maken, laten we onze decoder overeenkomen met de lokale publicationDate van de camelcase-case met de snake case- publication_date zoals geleverd door de API.

SwiftyJSON

SwiftyJSON is een Swift-framework dat is gebouwd om de noodzaak van optionele kettingvorming in normale JSON-serialisatie te verwijderen.

U kunt het hier downloaden: https://github.com/SwiftyJSON/SwiftyJSON

Zonder SwiftyJSON zou uw code er als volgt uitzien om de naam van het eerste boek in een JSON-object te vinden:

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
}

In SwiftyJSON is dit enorm vereenvoudigd:

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

Het elimineert de noodzaak om elk veld te controleren, want het zal nul retourneren als een van hen ongeldig is.

Om SwiftyJSON te gebruiken, downloadt u de juiste versie van de Git-repository - er is een tak voor Swift 3. Sleep eenvoudig de "SwiftyJSON.swift" naar uw project en importeer in uw klasse:

import SwiftyJSON

U kunt uw JSON-object maken met de volgende twee initializers:

let jsonObject = JSON(data: dataObject)

of

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

Gebruik subscripts om toegang te krijgen tot uw gegevens:

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

U kunt vervolgens uw waarde parseren naar een bepaald gegevenstype, dat een optionele waarde retourneert:

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

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

Je kunt je paden ook samenstellen in een snelle array:

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

Is hetzelfde als:

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

SwiftyJSON heeft ook functionaliteit om eigen fouten af te drukken:

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
}

Als u naar uw JSON-object moet schrijven, kunt u opnieuw subscripts gebruiken:

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

Als u de oorspronkelijke tekenreeks voor de JSON nodig hebt, bijvoorbeeld als u deze naar een bestand moet schrijven, kunt u de ruwe waarde eruit halen:

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 is een JSON-parsingbibliotheek die wordt beheerd door Big Nerd Ranch . Het heeft drie belangrijke voordelen:

  1. Type Veiligheid: helpt u bij het verzenden en ontvangen van JSON op een manier die crashes tijdens runtime voorkomt.

  2. Idiomatisch: profiteert van Swift's generieken, opsommingen en functionele functies, zonder ingewikkelde documentatie of magische aangepaste operatoren.

  3. Foutafhandeling: biedt informatieve foutinformatie voor veel voorkomende JSON-fouten.

Voorbeeld JSON-gegevens

Laten we enkele voorbeeld-JSON-gegevens definiëren voor gebruik met deze voorbeelden.

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

Ruwe gegevens deserialiseren

Om de gegevens te deserialiseren, initialiseren we een JSON object en openen vervolgens een bepaalde sleutel.

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

We try hier omdat toegang tot de json voor de sleutel "success" kan mislukken - het bestaat misschien niet, of de waarde is misschien geen Boolean.

We kunnen ook een pad opgeven voor toegang tot elementen die zijn genest in de JSON-structuur. Het pad is een door komma's gescheiden lijst met sleutels en indices die het pad naar een interessante waarde beschrijven.

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
}

Modellen rechtstreeks deserialiseren

JSON kan direct worden ontleed naar een JSONDecodable die het JSONDecodable protocol implementeert.

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
}

Ruwe gegevens serialiseren

Elke JSON waarde kan rechtstreeks naar NSData worden geserialiseerd.

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

Modellen rechtstreeks serialiseren

Elke JSONEncodable die het JSONEncodable protocol implementeert, kan rechtstreeks naar NSData worden geserialiseerd.

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

Pijl

Arrow is een elegante JSON-parsingbibliotheek in Swift.

Hiermee kunt u JSON ontleden en toewijzen aan aangepaste modelklassen met behulp van een <-- operator:

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

Voorbeeld:

Snel model

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

JSON-bestand

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

In kaart brengen

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

Gebruik

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

Installatie:

Carthago

github "s4cha/Arrow"

CocoaPods

pod 'Arrow'
use_frameworks!

handmatig

Kopieer en plak Arrow.swift in uw Xcode-project

https://github.com/s4cha/Arrow

Als een raamwerk

Download Arrow uit de GitHub-repository en bouw het Framework-doel op het voorbeeldproject. Koppel vervolgens dit kader.

Eenvoudige JSON-parsing in aangepaste objecten

Zelfs als bibliotheken van derden goed zijn, wordt een eenvoudige manier om de JSON te parseren geleverd door protocollen. Je kunt je voorstellen dat je een object Todo als

struct Todo {
    let comment: String
}

Telkens wanneer u de JSON ontvangt, kunt u de gewone NSData , zoals in het andere voorbeeld, met behulp van het NSJSONSerialization object.

Daarna, met behulp van een eenvoudig protocol JSONDecodable

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

En uw Todo structuur conform 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)
    }
}

Je kunt het proberen met deze json-code:

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

Wanneer u het van de API hebt gekregen, kunt u het serialiseren zoals de vorige voorbeelden in een AnyObject instantie. Daarna kunt u controleren of het exemplaar een JSONDictionary exemplaar is

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

Het andere ding om te controleren, specifiek voor dit geval omdat je een reeks Todo in de JSON hebt, is het todos woordenboek

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

Nu heb je de array van woordenboeken, kunt u elk van hen om te zetten in een Todo object met behulp van flatMap (het zal automatisch het verwijderen nil waarden uit de array)

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

JSON Parsing Swift 3

Hier is het JSON-bestand dat we animals.json zullen gebruiken

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

Importeer uw JSON-bestand in uw project

U kunt deze eenvoudige functie uitvoeren om uw JSON-bestand af te drukken

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

Als u het in een tabelweergave wilt plaatsen, zou ik eerst een woordenboek maken met een NSObject.

Maak een nieuw snel bestand met de naam ParsingObject en maak uw ParsingObject .

Zorg ervoor dat de variabelenaam hetzelfde is als het JSON-bestand

. In ons project hebben we bijvoorbeeld name en question dus in ons nieuwe snelle bestand zullen we gebruiken

var name: String?
var question: String?

Initialiseer het NSObject dat we terug hebben gemaakt in onze ViewController.swift var array = ParsingObject Dan zouden we dezelfde methode uitvoeren die we eerder hadden met een kleine wijziging.

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

Dan laten we het in ons tabeloverzicht zien door dit te doen,

    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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow