Swift Language
JSON lezen en schrijven
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.
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.
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
enDictionary
voldoen aanCodable
als zeCodable
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:
Type Veiligheid: helpt u bij het verzenden en ontvangen van JSON op een manier die crashes tijdens runtime voorkomt.
Idiomatisch: profiteert van Swift's generieken, opsommingen en functionele functies, zonder ingewikkelde documentatie of magische aangepaste operatoren.
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
}