Sök…


Syntax

  • NSJSONSerialization.JSONObjectWithData (jsonData, alternativ: NSJSONReadingOptions) // Returnerar ett objekt från jsonData. Denna metod kastar på misslyckande.
  • NSJSONSerialization.dataWithJSONObject (jsonObject, alternativ: NSJSONWritingOptions) // Returnerar NSData från ett JSON-objekt. Pass in NSJSONWritingOptions.PrettyPrinted i alternativ för en utgång som är mer läsbar.

JSON Serialisering, kodning och avkodning med Apple Foundation och Swift Standard Library

JSONSerialization- klassen är inbyggd i Apples Foundation-ramverk.

2,2

Läs JSON

Funktionen JSONObjectWithData tar NSData och returnerar AnyObject . Du kan använda as? för att konvertera resultatet till din förväntade typ.

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

Du kan skicka options: .AllowFragments istället för options: [] att tillåta läsning av JSON när toppnivån inte är en matris eller ordbok.

Skriv JSON

Ringa dataWithJSONObject konverterar ett JSON-kompatibelt objekt (kapslade matriser eller ordböcker med strängar, siffror och NSNull ) till råa NSData kodade som 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)")
}

Du kan skicka options: .PrettyPrinted istället för options: [] för vackert utskrift.

3,0

Samma beteende i Swift 3 men med en annan syntax.

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

Obs: Följande är för närvarande endast tillgängligt i Swift 4.0 och senare.

Från och med Swift 4.0 inkluderar Swift-standardbiblioteket protokollen Encodable och Decodable att definiera en standardiserad strategi för datakodning och avkodning. Att anta dessa protokoll tillåter implementering av Encoder och Decoder tar dina data och kodar eller avkodar dem till och från en extern representation såsom JSON. Överensstämmelse med Codable protokollet kombinerar både Encodable och Decodable protokoll. Detta är nu det rekommenderade sättet att hantera JSON i ditt program.

Koda och avkoda automatiskt

Det enklaste sättet att göra en typ kodbar är att förklara dess egenskaper som typer som redan är Codable . Dessa typer inkluderar standardbibliotekstyper som String , Int och Double ; och Foundation-typer som Date , Data och URL . Om egenskaperna för en typ är kodbara kommer själva typen att automatiskt överensstämma med Codable genom att helt enkelt förklara överensstämmelsen.

Betrakta följande exempel, i vilka Book struktur överensstämmer till Codable .

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

Observera att standardsamlingar som Array och Dictionary överensstämmer med Codable om de innehåller kodbara typer.

Genom att anta Codable den Book kan strukturen nu kodas till och avkodas från JSON med hjälp av Apple Foundation Classes JSONEncoder och JSONDecoder trots Book i sig innehåller ingen kod för att specifikt hantera JSON. Anpassade kodare och avkodare kan också skrivas genom att Encoder Decoder respektive avkodarprotokollen.

Koda till JSON-data

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

Ställ in encoder.outputFormatting = .prettyPrinted för enklare läsning. ## Avkodning från JSON-data

Avkoda från JSON-data

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

I exemplet Book.self informerar Book.self avkodaren om den typ som JSON ska avkodas till.

Kodning eller avkodning exklusivt

Ibland kanske du inte behöver data för att vara både kodbara och avkodningsbara, till exempel när du bara behöver läsa JSON-data från ett API, eller om ditt program bara skickar JSON-data till ett API.

Om du bara tänker skriva JSON-data ska du anpassa din typ till Encodable .

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

Om du bara tänker läsa JSON-data ska du anpassa din typ till Decodable .

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

Använda anpassade nyckelnamn

API: er använder ofta andra namnkonventioner än Swift-kamelväskan, till exempel ormfodral. Detta kan bli ett problem när det gäller att avkoda JSON, eftersom JSON-nycklarna som standard måste anpassa exakt till din typs egendomnamn. För att hantera dessa scenarier kan du skapa anpassade nycklar för din typ med CodingKey protokollet.

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

CodingKeys genereras automatiskt för typer som antar Codable protokollet, men genom att skapa vår egen implementering i exemplet ovan tillåter vi vår avkodare att matcha den lokala publicationDate av kamelfallsdatum med publication_date när den levereras av API.

SwiftyJSON

SwiftyJSON är ett Swift-ramverk som är byggt för att ta bort behovet av valfri kedja i normal JSON-seriellisering.

Du kan ladda ner det här: https://github.com/SwiftyJSON/SwiftyJSON

Utan SwiftyJSON skulle din kod se ut så här för att hitta namnet på den första boken i ett JSON-objekt:

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
}

I SwiftyJSON förenklas detta enormt:

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

Det tar bort behovet av att kontrollera alla fält, eftersom det kommer att returnera noll om någon av dem är ogiltiga.

För att använda SwiftyJSON, ladda ner rätt version från Git-förvaret - det finns en gren för Swift 3. Dra bara "SwiftyJSON.swift" till ditt projekt och importera till din klass:

import SwiftyJSON

Du kan skapa ditt JSON-objekt med följande två initialiseringar:

let jsonObject = JSON(data: dataObject)

eller

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

För att få åtkomst till dina data använder du abonnemang:

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

Du kan sedan para ditt värde till en viss datatyp, vilket kommer att returnera ett valfritt värde:

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

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

Du kan också sammanställa dina vägar till en snabb Array:

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

Är det samma som:

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

SwiftyJSON har också funktionalitet för att skriva ut sina egna fel:

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
}

Om du behöver skriva till ditt JSON-objekt kan du använda prenumerationer igen:

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

Om du behöver den ursprungliga strängen för JSON, till exempel om du behöver skriva den till en fil, kan du få ut råvärdet:

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 är ett JSON-analysbibliotek underhållet av Big Nerd Ranch . Det har tre huvudfördelar:

  1. Typsäkerhet: Hjälper dig att arbeta med att skicka och ta emot JSON på ett sätt som förhindrar runtime-krasch.

  2. Idiomatisk: Utnyttjar Swifts generika, uppräkningar och funktionella funktioner, utan komplicerad dokumentation eller magiska anpassade operatörer.

  3. Felhantering: Tillhandahåller informativ felinformation för vanliga JSON-fel.

Exempel JSON-data

Låt oss definiera några exempel på JSON-data för användning med dessa exempel.

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

Deserializing Raw Data

För att deserialisera data, initialiserar vi ett JSON objekt och JSON sedan en viss nyckel.

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

Vi try här eftersom åtkomst till json för nyckeln "success" kan misslyckas - det kanske inte finns, eller värdet kanske inte är en booleska.

Vi kan också ange en sökväg för åtkomstelement som är kapslade i JSON-strukturen. Sökvägen är en kommaseparerad lista med nycklar och index som beskriver sökvägen till ett intressevärde.

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
}

Deserialisering av modeller direkt

JSON kan direkt analyseras till en JSONDecodable som implementerar JSONDecodable protokollet.

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
}

Serialisera rå data

Alla JSON värden kan serialiseras direkt till NSData .

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

Serialiserar modeller direkt

Alla JSONEncodable som implementerar JSONEncodable protokollet kan serialiseras direkt till 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()

Pil

Arrow är ett elegant JSON-parsing-bibliotek i Swift.

Det gör det möjligt att analysera JSON och kartlägga den till anpassade modellklasser med hjälp av en <-- operatör:

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

Exempel:

Snabb modell

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

JSON-fil

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

kartläggning

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

Användande

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

Installation:

Carthage

github "s4cha/Arrow"

CocoaPods

pod 'Arrow'
use_frameworks!

Manuellt

Kopiera och klistra in Arrow.swift i ditt Xcode-projekt

https://github.com/s4cha/Arrow

Som ett ramverk

Ladda ner Arrow från GitHub-lagret och bygg ramverkets mål på exempelprojektet. Länk sedan mot denna ram.

Enkel JSON-analysering i anpassade objekt

Även om tredjepartsbibliotek är bra, tillhandahålls ett enkelt sätt att analysera JSON genom protokoll. Du kan föreställa dig att du har ett objekt Todo som

struct Todo {
    let comment: String
}

När du får JSON kan du hantera vanliga NSData som visas i det andra exemplet med NSJSONSerialization objekt.

Efter det med ett enkelt protokoll JSONDecodable

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

Och att göra din Todo struktur överensstämmer med JSONDecodable gör tricket

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

Du kan prova det med den här jsonkoden:

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

När du fick det från API: n kan du serialisera det som de tidigare exemplen som visas i en AnyObject instans. Efter det kan du kontrollera om instansen är en JSONDictionary instans

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

Det andra att kontrollera, specifikt för detta fall eftersom du har en rad Todo i JSON, är todos ordboken

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

Nu när du har fått uppsättningen ordböcker kan du konvertera var och en av dem i ett Todo objekt med hjälp av flatMap (det raderar automatiskt nil från arrayen)

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

JSON Parsing Swift 3

Här är JSON-filen som vi kommer att använda som heter 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?"
    }   ] }

Importera din JSON-fil i ditt projekt

Du kan utföra den här enkla funktionen för att skriva ut din JSON-fil

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

Om du vill lägga den i en tabellvy skulle jag skapa en ordbok först med ett NSObject.

Skapa en ny ParsingObject heter ParsingObject och skapa dina strängvariabler.

Se till att variabelns namn är samma som JSON-filen

. I vårt projekt har vi till exempel name och question så i vår nya snabbfil kommer vi att använda

var name: String?
var question: String?

Initialisera NSObject som vi gjorde tillbaka till vår ViewController.swift var array = ParsingObject Sedan skulle vi utföra samma metod som vi hade tidigare med en mindre modifiering.

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

Sedan visar vi det i vår tabellvisning genom att göra detta,

    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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow