Szukaj…


Składnia

  • NSJSONSerialization.JSONObjectWithData (jsonData, opcje: NSJSONReadingOptions) // Zwraca obiekt z jsonData. Ta metoda powoduje awarię.
  • NSJSONSerialization.dataWithJSONObject (jsonObject, opcje: NSJSONWritingOptions) // Zwraca NSData z obiektu JSON. Przekaż w NSJSONWritingOptions.PrettyPrinted w opcjach dla bardziej czytelnego wyniku.

Serializacja, kodowanie i dekodowanie JSON w Apple Foundation i Swift Standard Library

Klasa JSONSerialization jest wbudowana w środowisko Apple Foundation.

2.2

Przeczytaj JSON

Funkcja JSONObjectWithData pobiera NSData i zwraca AnyObject . Możesz użyć as? przekonwertować wynik na oczekiwany 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)")
}

Możesz przekazać options: .AllowFragments zamiast options: [] aby umożliwić odczyt JSON, gdy obiekt najwyższego poziomu nie jest tablicą ani słownikiem.

Napisz JSON

Wywołanie dataWithJSONObject konwertuje obiekt zgodny z JSON (zagnieżdżone tablice lub słowniki z ciągami, liczbami i NSNull ) na surowe NSData zakodowane jako 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)")
}

Możesz przekazać options: .PrettyPrinted zamiast options: [] do ładnego drukowania.

3.0

Takie samo zachowanie w Swift 3, ale z inną składnią.

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

Uwaga: Poniższe jest obecnie dostępne tylko w Swift 4.0 i nowszych.

Począwszy od Swift 4.0, standardowa biblioteka Swift zawiera protokoły Encodable i Decodable celu zdefiniowania standardowego podejścia do kodowania i dekodowania danych. Przyjmując te protokoły pozwoli implementacje Encoder i Decoder protokołów zabrać swoje dane i zakodować lub odkodować go i od reprezentacji zewnętrznej, takich jak JSON. Zgodność z protokołem Codable łączy protokoły Encodable i Decodable . Jest to obecnie zalecany sposób obsługi JSON w twoim programie.

Automatyczne kodowanie i dekodowanie

Najłatwiejszym sposobem na Codable typu jest zadeklarowanie jego właściwości jako typów, które są już Codable . Te typy obejmują standardowe typy bibliotek, takie jak String , Int i Double ; oraz typy Fundacji, takie jak Date , Data i URL . Jeśli właściwości typu są kodowalne, sam typ automatycznie dostosuje się do Codable , po prostu deklarując zgodność.

Rozważ następujący przykład, w którym struktura Book jest zgodna z Codable .

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

Zauważ, że standardowe kolekcje, takie jak Array i Dictionary są zgodne z Codable jeśli zawierają typy Codable .

Dzięki przyjęciu Codable , struktura Book może być teraz kodowana i dekodowana z JSON przy użyciu klas Apple Foundation JSONEncoder i JSONDecoder , mimo że sama Book nie zawiera kodu do specyficznej obsługi JSON. Niestandardowe kodery i dekodery można również zapisywać, odpowiednio dostosowując się do protokołów Encoder i Decoder .

Zakoduj do danych 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)

Ustaw encoder.outputFormatting = .prettyPrinted dla łatwiejszego czytania. ## Dekoduj z danych JSON

Dekoduj z danych 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)

W powyższym przykładzie Book.self informuje dekoder o typie, do którego należy dekodować JSON.

Wyłącznie kodowanie lub dekodowanie

Czasami dane mogą nie być zarówno kodowalne, jak i dekodowalne, na przykład gdy potrzebujesz tylko odczytać dane JSON z interfejsu API lub jeśli twój program przesyła tylko dane JSON do interfejsu API.

Jeśli zamierzasz tylko zapisywać dane JSON, dostosuj swój typ do Encodable .

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

Jeśli zamierzasz tylko czytać dane JSON, dostosuj swój typ do Decodable .

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

Używanie niestandardowych nazw kluczy

Interfejsy API często stosują konwencje nazewnictwa inne niż standardowe etui na wielbłądy Swift, takie jak przypadek węża. Może to stanowić problem przy dekodowaniu JSON, ponieważ domyślnie klucze JSON muszą być dokładnie dopasowane do nazw właściwości twojego typu. Aby obsłużyć te scenariusze, możesz utworzyć niestandardowe klucze dla swojego typu za pomocą protokołu CodingKey .

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

CodingKeys są generowane automatycznie dla typów, które przyjmują protokół Codable , ale tworząc własną implementację w powyższym przykładzie, pozwalamy naszemu dekoderowi dopasować lokalną publicationDate skrzynki na wielbłądy z Codable węża w przypadku publication_date ponieważ jest ona dostarczana przez interfejs API.

SwiftyJSON

SwiftyJSON to platforma Swift zbudowana w celu wyeliminowania potrzeby opcjonalnego łączenia w normalną serializację JSON.

Możesz go pobrać tutaj: https://github.com/SwiftyJSON/SwiftyJSON

Bez SwiftyJSON Twój kod wyglądałby tak, aby znaleźć nazwę pierwszej książki w obiekcie 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
}

W SwiftyJSON jest to bardzo uproszczone:

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

Eliminuje to konieczność sprawdzania każdego pola, ponieważ zwróci zero, jeśli którekolwiek z nich jest nieprawidłowe.

Aby użyć SwiftyJSON, pobierz poprawną wersję z repozytorium Git - istnieje gałąź dla Swift 3. Po prostu przeciągnij „SwiftyJSON.swift” do swojego projektu i zaimportuj do swojej klasy:

import SwiftyJSON

Możesz utworzyć obiekt JSON przy użyciu następujących dwóch inicjatorów:

let jsonObject = JSON(data: dataObject)

lub

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

Aby uzyskać dostęp do swoich danych, użyj indeksów dolnych:

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

Następnie możesz przeanalizować swoją wartość do określonego typu danych, który zwróci wartość opcjonalną:

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

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

Możesz także skompilować swoje ścieżki w szybką tablicę:

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

Jest taki sam jak:

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

SwiftyJSON ma również funkcję drukowania własnych błędów:

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
}

Jeśli chcesz napisać do obiektu JSON, możesz ponownie użyć indeksów dolnych:

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

Jeśli potrzebujesz oryginalnego ciągu dla JSON, na przykład jeśli chcesz go zapisać do pliku, możesz uzyskać surową wartość:

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 to biblioteka parsująca JSON prowadzona przez Big Nerd Ranch . Ma trzy główne zalety:

  1. Bezpieczeństwo typu: pomaga w pracy z wysyłaniem i odbieraniem JSON w sposób zapobiegający awariom w czasie wykonywania.

  2. Idiomatic: Wykorzystuje cechy ogólne, wyliczenia i funkcje funkcjonalne Swift, bez skomplikowanej dokumentacji ani magicznych niestandardowych operatorów.

  3. Obsługa błędów: Zawiera informacje o błędach typowych błędów JSON.

Przykładowe dane JSON

Zdefiniujmy przykładowe dane JSON do użycia z tymi przykładami.

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

Deserializowanie surowych danych

Aby dokonać deserializacji danych, inicjujemy obiekt JSON a następnie uzyskujemy dostęp do określonego klucza.

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

try tutaj, ponieważ dostęp do json dla klucza "success" może się nie powieść - może nie istnieć lub wartość może nie być wartością logiczną.

Możemy również określić ścieżkę dostępu do elementów zagnieżdżonych w strukturze JSON. Ścieżka to rozdzielona przecinkami lista kluczy i indeksów opisujących ścieżkę do interesującej wartości.

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
}

Bezpośrednia deserializacja modeli

JSON można bezpośrednio parsować do klasy modelu, która implementuje protokół 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
}

Serializacja surowych danych

Każda wartość JSON może być serializowana bezpośrednio do NSData .

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

Bezpośrednie serializowanie modeli

Każda klasa modelu, która implementuje protokół JSONEncodable , może być serializowana bezpośrednio do 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()

Strzałka

Arrow to elegancka biblioteka parsująca JSON w Swift.

Pozwala na parsowanie JSON i mapowanie go do niestandardowych klas modeli za pomocą operatora <-- :

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

Przykład:

Szybki model

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

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

Mapowanie

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

Stosowanie

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

Instalacja:

Kartagina

github "s4cha/Arrow"

CocoaPods

pod 'Arrow'
use_frameworks!

Ręcznie

Po prostu skopiuj i wklej Arrow.swift w swoim projekcie Xcode

https://github.com/s4cha/Arrow

Jako ramy

Pobierz Arrow z repozytorium GitHub i zbuduj cel Framework na przykładowym projekcie. Następnie połącz z tymi ramami.

Proste parsowanie JSON do niestandardowych obiektów

Nawet jeśli biblioteki innych firm są dobre, protokoły zapewniają prosty sposób na parsowanie JSON. Możesz sobie wyobrazić, że masz obiekt Todo jako

struct Todo {
    let comment: String
}

Ilekroć otrzymasz JSON, możesz obsłużyć zwykły NSData jak pokazano w innym przykładzie, używając obiektu NSJSONSerialization .

Następnie za pomocą prostego protokołu JSONDecodable

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

I sprawienie, by struktura Todo zgodna z 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)
    }
}

Możesz spróbować z tym kodem json:

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

Po otrzymaniu go z interfejsu API można go serializować, tak jak w poprzednich przykładach pokazanych w instancji AnyObject . Następnie możesz sprawdzić, czy instancja jest instancją JSONDictionary

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

Inną rzeczą do sprawdzenia, specyficzną dla tego przypadku, ponieważ masz tablicę Todo w JSON, jest słownik todos

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

Teraz, gdy masz tablicę słowników, możesz przekonwertować każdy z nich w obiekt Todo za pomocą flatMap (automatycznie usunie wartości nil z tablicy)

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

JSON Parsing Swift 3

Oto plik JSON, którego będziemy używać, o nazwie 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?"
    }   ] }

Zaimportuj plik JSON do swojego projektu

Możesz wykonać tę prostą funkcję, aby wydrukować plik 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)
                }
           }
       }
    }

Jeśli chcesz umieścić go w widoku tabeli, najpierw stworzę słownik z obiektem NSObject.

Utwórz nowy szybki plik o nazwie ParsingObject i utwórz zmienne łańcuchowe.

Upewnij się, że nazwa zmiennej jest taka sama jak plik JSON

. Na przykład w naszym projekcie mamy name i question więc użyjemy go w naszym nowym pliku szybkim

var name: String?
var question: String?

Zainicjuj obiekt NSObject, który utworzyliśmy z powrotem w naszym var var ViewController.swift = ParsingObject Następnie wykonamy tę samą metodę, którą mieliśmy wcześniej, z niewielką modyfikacją.

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

Następnie pokazujemy to w naszym widoku tabeli, robiąc to,

    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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow