Swift Language
JSON lesen und schreiben
Suche…
Syntax
- NSJSONSerialization.JSONObjectWithData (jsonData, Optionen: NSJSONReadingOptions) // Gibt ein Objekt aus jsonData zurück. Diese Methode löst bei einem Fehler aus.
- NSJSONSerialization.dataWithJSONObject (jsonObject, Optionen: NSJSONWritingOptions) // Gibt NSData aus einem JSON-Objekt zurück. Übergeben Sie NSJSONWritingOptions.PrettyPrinted in Optionen für eine Ausgabe, die besser lesbar ist.
JSON-Serialisierung, Kodierung und Dekodierung mit Apple Foundation und der Swift Standard Library
Die JSONSerialization- Klasse ist in das Foundation-Framework von Apple integriert.
Lesen Sie JSON
Die JSONObjectWithData
Funktion verwendet NSData
und gibt AnyObject
. Sie können as?
um das Ergebnis in Ihren erwarteten Typ zu konvertieren.
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)")
}
Sie können options: .AllowFragments
anstelle von options: []
, um das Lesen von JSON zuzulassen, wenn das Objekt der obersten Ebene kein Array oder Wörterbuch ist.
Schreibe JSON
Beim Aufruf von dataWithJSONObject
wird ein JSON-kompatibles Objekt (verschachtelte Arrays oder Wörterbücher mit Zeichenfolgen, Zahlen und NSNull
) in als NSData
kodierte NSData
NSNull
dataWithJSONObject
konvertiert.
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)")
}
Sie können options: .PrettyPrinted
anstelle von options: []
für das hübsche Drucken.
Gleiches Verhalten in Swift 3, jedoch mit anderer 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)")
}
Hinweis: Das Folgende ist derzeit nur in Swift 4.0 und höher verfügbar.
Ab Swift 4.0 enthält die Swift-Standardbibliothek die Protokolle Encodable
und Decodable
, um einen standardisierten Ansatz für die Encodable
und Decodable
zu definieren. Die Übernahme dieser Protokolle ermöglicht Implementierungen der Encoder
und Decoder
Protokolle, die Ihre Daten verschlüsseln oder von einer externen Repräsentation wie JSON codieren oder decodieren. Die Konformität mit dem Codable
Protokoll kombiniert die Protokolle Encodable
und Decodable
. Dies ist jetzt die empfohlene Methode, um JSON in Ihrem Programm zu behandeln.
Automatisch codieren und decodieren
Die einfachste Möglichkeit, einen Typ codierbar zu machen, besteht darin, seine Eigenschaften als Typen zu definieren, die bereits Codable
. Diese Typen umfassen Standardbibliothekstypen wie String
, Int
und Double
; und Foundation-Typen wie Date
, Data
und URL
. Wenn die Eigenschaften eines Typs codierbar sind, entspricht der Typ selbst automatisch der Codable
indem er einfach die Konformität erklärt.
Betrachten Sie das folgende Beispiel, in dem die Book
Struktur mit Codable
.
struct Book: Codable {
let title: String
let authors: [String]
let publicationDate: Date
}
Beachten Sie, dass Standardsammlungen wie
Array
undDictionary
mitCodable
übereinstimmen, wenn sie codierbare Typen enthalten.
Durch die Codable
von Codable
kann die Book
Struktur jetzt mit den Apple Foundation-Klassen JSONEncoder
und JSONDecoder
JSON codiert und daraus decodiert werden, obwohl Book
selbst keinen Code für die spezifische Verarbeitung von JSON enthält. Benutzerdefinierte Encoder und Decoder können ebenfalls geschrieben werden, indem sie den Protokollen Encoder
bzw. Decoder
entsprechen.
In JSON-Daten kodieren
// 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
Sieencoder.outputFormatting = .prettyPrinted
um das Lesen zu erleichtern. ## Aus JSON-Daten dekodieren
Aus JSON-Daten decodieren
// 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)
Im obigen Beispiel informiert
Book.self
den Decoder über den Typ, in den der JSON decodiert werden soll.
Ausschließlich kodieren oder dekodieren
In manchen Fällen müssen Daten möglicherweise nicht sowohl kodierbar als auch dekodierbar sein, z. B. wenn Sie nur JSON-Daten von einer API lesen oder Ihr Programm nur JSON-Daten an eine API sendet.
Wenn Sie nur JSON-Daten schreiben Encodable
, Encodable
Ihren Typ an Encodable
.
struct Book: Encodable {
let title: String
let authors: [String]
let publicationDate: Date
}
Wenn Sie nur JSON-Daten lesen Decodable
, Decodable
Ihren Typ an Decodable
.
struct Book: Decodable {
let title: String
let authors: [String]
let publicationDate: Date
}
Benutzerdefinierte Tastennamen verwenden
APIs verwenden häufig andere Namenskonventionen als den Kamel-Fall nach Swift-Standard, beispielsweise den Fall mit Schlangen. Dies kann zu einem Problem bei der Dekodierung von JSON werden, da die JSON-Schlüssel standardmäßig genau mit den Eigenschaftsnamen Ihres Typs übereinstimmen müssen. Um mit diesen Szenarien umgehen zu können, können Sie mithilfe des CodingKey
Protokolls benutzerdefinierte Schlüssel für Ihren Typ CodingKey
.
struct Book: Codable {
// ...
enum CodingKeys: String, CodingKey {
case title
case authors
case publicationDate = "publication_date"
}
}
CodingKeys
werden automatisch für Typen erzeugt , die das annehmen Codable
Protokoll, sondern durch unsere eigene Implementierung in dem Beispiel die Schaffung oben wir zulassen , dass unsere Decoder den lokalen Kamel Fall übereinstimmen publicationDate
mit der Schlange Fall publication_date
wie sie von der API geliefert wird .
SwiftyJSON
SwiftyJSON ist ein Swift-Framework, das die Notwendigkeit einer optionalen Verkettung bei der normalen JSON-Serialisierung beseitigt.
Sie können es hier herunterladen: https://github.com/SwiftyJSON/SwiftyJSON
Ohne SwiftyJSON würde Ihr Code so aussehen, um den Namen des ersten Buches in einem JSON-Objekt zu finden:
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 ist dies enorm vereinfacht:
let json = JSON(data: data)
if let bookName = json[0]["book"]["name"].string {
//We can now use the book name
}
Dadurch entfällt die Notwendigkeit, jedes Feld zu überprüfen, da es null zurückgibt, wenn eines der Felder ungültig ist.
Um SwiftyJSON zu verwenden, laden Sie die korrekte Version aus dem Git-Repository herunter. Es gibt einen Zweig für Swift 3. Ziehen Sie einfach die "SwiftyJSON.swift" in Ihr Projekt und importieren Sie sie in Ihre Klasse:
import SwiftyJSON
Sie können Ihr JSON-Objekt mithilfe der folgenden zwei Initialisierer erstellen:
let jsonObject = JSON(data: dataObject)
oder
let jsonObject = JSON(jsonObject) //This could be a string in a JSON format for example
Um auf Ihre Daten zuzugreifen, verwenden Sie Indizes:
let firstObjectInAnArray = jsonObject[0]
let nameOfFirstObject = jsonObject[0]["name"]
Sie können Ihren Wert dann zu einem bestimmten Datentyp parsen, der einen optionalen Wert zurückgibt:
let nameOfFirstObject = jsonObject[0]["name"].string //This will return the name as a string
let nameOfFirstObject = jsonObject[0]["name"].double //This will return null
Sie können Ihre Pfade auch in ein schnelles Array kompilieren:
let convolutedPath = jsonObject[0]["name"][2]["lastName"]["firstLetter"].string
Ist das gleiche wie:
let convolutedPath = jsonObject[0, "name", 2, "lastName", "firstLetter"].string
SwiftyJSON bietet auch Funktionen zum Drucken eigener Fehler:
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
}
Wenn Sie in Ihr JSON-Objekt schreiben müssen, können Sie erneut Subskripte verwenden:
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
Wenn Sie den ursprünglichen String für den JSON benötigen, zum Beispiel, wenn Sie ihn in eine Datei schreiben müssen, können Sie den Rohwert erhalten:
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 ist eine JSON-Parsing-Bibliothek, die von der Big Nerd Ranch verwaltet wird . Es hat drei Hauptvorteile:
Typensicherheit: Hilft Ihnen beim Senden und Empfangen von JSON auf eine Weise, die Laufzeitabstürze verhindert.
Idiomatic: Nutzen Sie die Generika, Aufzählungen und Funktionsmerkmale von Swift, ohne komplizierte Dokumentation oder magische benutzerdefinierte Operatoren.
Fehlerbehandlung: Enthält informative Fehlerinformationen für häufig auftretende JSON-Fehler.
Beispiel JSON-Daten
Definieren wir einige JSON-Beispieldaten für diese Beispiele.
{ "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)!
Rohdaten deserialisieren
Um die Daten zu deserialisieren, initialisieren wir ein JSON
Objekt und greifen dann auf einen bestimmten Schlüssel zu.
do { let json = try JSON(data: jsonData) let success = try json.bool("success") } catch { // do something with the error }
Wir try
hier, weil der Zugriff auf den json
für den Schlüssel "success"
fehlschlagen könnte - er existiert möglicherweise nicht oder der Wert ist möglicherweise nicht boolean.
Wir können auch einen Pfad angeben, um auf Elemente zuzugreifen, die in der JSON-Struktur verschachtelt sind. Der Pfad ist eine durch Kommas getrennte Liste von Schlüsseln und Indizes, die den Pfad zu einem interessierenden Wert beschreiben.
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 }
Modelle direkt deserialisieren
JSON kann direkt in eine Modellklasse analysiert werden, die das JSONDecodable
Protokoll implementiert.
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 }
Serialisierung von Rohdaten
Jeder JSON
Wert kann direkt in NSData
serialisiert werden.
let success = JSON.Bool(false) let data: NSData = try success.serialize()
Direktes Serialisieren von Modellen
Jede Modellklasse, die das JSONEncodable
Protokoll implementiert, kann direkt in NSData
serialisiert werden.
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()
Pfeil
Arrow ist eine elegante JSON-Parsing-Bibliothek in Swift.
Es erlaubt, JSON zu parsen und mit Hilfe eines <--
Operators benutzerdefinierten Modellklassen zuzuordnen:
identifier <-- json["id"]
name <-- json["name"]
stats <-- json["stats"]
Beispiel:
Schnelles Modell
struct Profile {
var identifier = 0
var name = ""
var link: NSURL?
var weekday: WeekDay = .Monday
var stats = Stats()
var phoneNumbers = [PhoneNumber]()
}
JSON-Datei
{
"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"
}]
}
Kartierung
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"]
}
}
Verwendungszweck
let profile = Profile()
profile.deserialize(json)
Installation:
Karthago
github "s4cha/Arrow"
Kakaopods
pod 'Arrow'
use_frameworks!
Manuell
Kopieren Sie einfach Arrow.swift in Ihr Xcode-Projekt
https://github.com/s4cha/Arrow
Als Rahmen
Laden Sie Arrow aus dem GitHub-Repository herunter und erstellen Sie das Framework-Ziel für das Beispielprojekt. Dann Link gegen diesen Rahmen.
Einfache JSON-Analyse in benutzerdefinierte Objekte
Selbst wenn Bibliotheken von Drittanbietern gut sind, bieten Protokolle eine einfache Möglichkeit zum Analysieren der JSON. Sie können sich vorstellen, dass Sie ein Objekt als Todo
struct Todo {
let comment: String
}
Wenn Sie den JSON erhalten, können Sie die einfachen NSData
wie im anderen Beispiel mit dem NSJSONSerialization
Objekt behandeln.
Danach mit einem einfachen Protokoll JSONDecodable
typealias JSONDictionary = [String:AnyObject]
protocol JSONDecodable {
associatedtype Element
static func from(json json: JSONDictionary) -> Element?
}
Und JSONDecodable
Ihre Todo
Struktur JSONDecodable
konform machen, können JSONDecodable
dies 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)
}
}
Sie können es mit diesem Json-Code versuchen:
{
"todos": [
{
"comment" : "The todo comment"
}
]
}
Wenn Sie es von der API erhalten haben, können Sie es wie in den vorherigen Beispielen in einer AnyObject
Instanz AnyObject
. Danach können Sie überprüfen, ob es sich bei der Instanz um eine JSONDictionary
Instanz handelt
guard let jsonDictionary = dictionary as? JSONDictionary else { return }
Die andere Sache, die speziell für diesen Fall geprüft werden muss, weil Sie ein Todo
Array in der JSON haben, ist das todos
Wörterbuch
guard let todosDictionary = jsonDictionary["todos"] as? [JSONDictionary] else { return }
Nun , da Sie das Array von Wörterbüchern erhalten haben, können Sie jede von ihnen in einem konvertieren Todo
Objekt unter Verwendung flatMap
(es wird automatisch die löschen nil
Werte aus dem Array)
let todos: [Todo] = todosDictionary.flatMap { Todo.from(json: $0) }
JSON Parsing Swift 3
Hier ist die JSON-Datei, die wir als 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?"
} ] }
Importieren Sie Ihre JSON-Datei in Ihr Projekt
Sie können diese einfache Funktion ausführen, um Ihre JSON-Datei auszudrucken
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)
}
}
}
}
Wenn Sie es in eine Tabellenansicht einfügen möchten, würde ich zuerst ein Wörterbuch mit einem NSObject erstellen.
Erstellen Sie eine neue Swift-Datei mit dem Namen ParsingObject
und erstellen Sie Ihre String-Variablen.
Stellen Sie sicher, dass der Variablenname der JSON-Datei entspricht
. Zum Beispiel haben wir in unserem Projekt einen name
und eine question
so dass wir sie in unserer neuen Swift-Datei verwenden werden
var name: String?
var question: String?
Initialisieren Sie das NSObject, das wir in ViewController.swift erstellt haben. Var array = ParsingObject Dann würden wir dieselbe Methode ausführen, die wir zuvor mit einer geringfügigen Modifikation verwendet haben.
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)
}
}
Dann zeigen wir es in unserer Tabellenansicht,
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
}