I'm trying print data from my response but there is an error - json

I can print only 1 data, not any more. This is my error:
Thread 1: Fatal error: Index out of range
This is my JSON:
[
{
"Guides": [
{
"_id": "5cbc780edfdb6307006aec37",
"Text": "He is one of Soroush Friend",
"Tavernier": 2
},
{
"_id": "5cbc781bdfdb6307006aec38",
"Text": "He is one of Soroush Friend",
"Tavernier": 2
}
]
}
]
And this is my struct that works well:
struct GuideStruct: Codable {
let guides: [Guide]
enum CodingKeys: String, CodingKey {
case guides = "Guides"
}
}
struct Guide: Codable {
let id, text: String
let tavernier: Int
enum CodingKeys: String, CodingKey {
case id = "_id"
case text = "Text"
case tavernier = "Tavernier"
}
}
And this is my array and my class:
internal static var guides = [guidesarr]()
class guidesarr {
var _id : String
var Text : String
var Tavernier : Int
init(_id : String,Text : String,Tavernier : Int) {
self._id = _id
self.Text = Text
self.Tavernier = Tavernier
}
}
And my codes in viewcontroller:
class GameViewController: UIViewController,UITextFieldDelegate {
typealias guide1 = [GuideStruct]
var i1 = 0
override func viewDidLoad() {
super.viewDidLoad()
let headers : HTTPHeaders = ["Content-Type":"application/json","OAtcp":"0!QSJ5SDG8Q39PPM$DXP5HD1E10"]
Alamofire.request("http://192.168.1.100:3535/DarkDiamonds/Api/GetActiveGames",method :.post,headers: headers).responseJSON { (newresponse) in
do {
let decoder = JSONDecoder()
let responseguide = try decoder.decode(guide1.self, from: newresponse.data!)
for each1 in responseguide {
let newstruct = guidesarr(_id:each1.guides[self.i1].id , Text: each1.guides[self.i1].text, Tavernier: each1.guides[self.i1].tavernier)
self.i1 = self.i1 + 1
AppDelegate.guides.append(newstruct)
}
print(AppDelegate.guides[0])
print(AppDelegate.guides[1])
print(AppDelegate.Games.count)
print(AppDelegate.guides[0].Text)
print(AppDelegate.guides[1].Text)
}catch {
}
}
}
}
I can print:
print(AppDelegate.guides[0])
And print this:
print(AppDelegate.guides[0].Text)
But when I want to print this:
print(AppDelegate.guides[1])
print(AppDelegate.guides[1].Text)
There is error:
Thread 1: Fatal error: Index out of range

There are several issues in your code.
The guidesarr class is unnecessary. Just use your Guide struct.
Use proper naming conventions. Class, struct, and enum names should start with uppercase letters. Property, function, and case names should start with lowercase letters.
Don't force-unwrap data. Safely check it and do proper error checking.
Your main issue is that the two chunks of data you seem to actually want are the two Guide instances inside the one (not two) GuideStruct instances.
I would redo your code something like this:
class GameViewController: UIViewController,UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let headers : HTTPHeaders = ["Content-Type":"application/json","OAtcp":"0!QSJ5SDG8Q39PPM$DXP5HD1E10"]
Alamofire.request("http://192.168.1.100:3535/DarkDiamonds/Api/GetActiveGames", method: .post, headers: headers).responseJSON { (newresponse) in
if let data = newresponse.data {
do {
let decoder = JSONDecoder()
let guides = try decoder.decode([GuideStruct].self, from: data)
for guideStruct in guides {
AppDelegate.guides.append(contentsOf: guideStruct.guides)
}
print(AppDelegate.guides[0])
print(AppDelegate.guides[1])
print(AppDelegate.Games.count)
print(AppDelegate.guides[0].Text)
print(AppDelegate.guides[1].Text)
}catch {
// Bad JSON
}
} else {
// No data
}
}
}
}
And change:
internal static var guides = [guidesarr]()
to:
internal static var guides = [Guide]()
And delete the guidearr class.

Related

TypeMismatch error in filling List from JSON

i am trying to fill a list from JSON in SwiftUI, which has this format:
{
"books": [{
"id": "87",
"title": "2001 odissea nello spazio",
"author_id": null,
"author": "arthur c. clarke",
"editor_id": null,
"editor": "longanesi",
"price": "0.00",
"isbn": "",
"note": ""
}, ......]
}
i created this struct for the Book object:
struct Book: Decodable, Identifiable {
public var id: Int;
public var title: String;
public var isbn: String;
enum CodingKeys: String, CodingKey {
case id = "id";
case title = "title";
case isbn = "isbn";
}
}
then i created this class to get the remote json:
import Foundation
public class GetBooks: ObservableObject {
#Published var books = [Book]();
init() {
load();
}
func load() {
let url = URL(string: "https://www.mattepuffo.com/api/book/get.php")!;
URLSession.shared.dataTask(with: url) {
(data, response, error) in
do {
if let d = data {
let decodedLists = JSONDecoder();
decodedLists.keyDecodingStrategy = .convertFromSnakeCase;
let dec = try decodedLists.decode([Book].self, from: d);
DispatchQueue.main.async {
self.books = dec;
}
} else {
print("Non ci sono libri");
}
} catch {
print(error)
}
}.resume();
}
}
but i get an error: typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))
I think I understand what the problem is, but I don't understand how to solve it.
in the sense that the problem is that the json starts with an object (books) and not with an array.
but I don't understand how I have to modify the code!
I also tried to modify this line in this way, getting the error you see in the comment:
let dec = try decodedLists.decode(Book.self, from: d);
DispatchQueue.main.async {
self.books = dec; // Cannot assign value of type 'Book' to type '[Book]'
}
Your problem is that your JSON is not an Array of Book.
You need an upper level struct:
struct BookList: Decodable {
let books : [Book]
}
and then decode this structure instead of the array:
let dec = try decodedLists.decode(BookList.self, from: d);
DispatchQueue.main.async {
self.books = dec.books;
}
There are two major issues in your code:
You are ignoring the root object of the JSON, the dictionary with key books. This causes the error.
The type of key id is a string, in JSON everything in double quotes is String.
Further you don't need CodingKeys if all struct member names match the JSON keys and if the struct members are not going to be modified declare them as constants (let). Finally this is Swift: No trailing objective-c-ish semicolons.
struct Root: Decodable {
public let books: [Book]
}
struct Book: Decodable, Identifiable {
public let id: String
public let title: String
public let isbn: String
}
let result = try decodedLists.decode(Root.self, from: d)
DispatchQueue.main.async {
self.books = result.books
}

reduce function is printing an empty dictionary [:]

I have reduced my dictionary keys successfully in this question as pseudo-code without a real json model. The goal which I accomplished in the previous question is to return only the keys that have matching values. So the output is a dictionary that looks something like this ["WoW": ["#jade", "#kalel"]. Exactly what I needed. Of course there could be other matches and I'd like to return those as well.
Now that I have a proper json model, the reduce function is printing out an empty dictionary [:]. Is it the type in .reduce(into: [String:[String]]() that is causing the issue?
All the data is printing so the json and model structure must be correct.
json
[
{
"id": "tokenID-tqkif48",
"name": "#jade",
"game": "WoW",
"age": "18"
},
{
"id": "tokenID-fvkif21",
"name": "#kalel",
"game": "WoW",
"age": "20"
}
]
UserModel
public typealias Users = [UserModel]
public struct UserModel: Codable {
public let name: String
public let game: String
// etc...
enum CodingKeys: String, CodingKey {
case name
case game
// etc...
Playground
guard let url = Bundle.main.url(forResource: "Users", withExtension: "json") else {
fatalError()
}
guard let data = try? Data(contentsOf: url) else {
fatalError()
}
let decoder = JSONDecoder()
do {
let response = try decoder.decode([UserModel].self, from: data)
for userModel in response {
let userDict: [String:String] = [ userModel.name:userModel.game ]
let reduction = Dictionary(grouping: userDict.keys) { userDict[$0] ?? "" }.reduce(into: [String:[String]](), { (result, element) in
if element.value.count > 1 {
result[element.key] = element.value
}
})
// error catch etc
}
Your code is too complicated. You can group the array by game simply with
let response = try decoder.decode([UserModel].self, from: data)
let reduction = Dictionary(grouping: response, by: {$0.game}).mapValues{ usermodel in usermodel.map{ $0.name}}
UPDATE I may be mistaking what you want to get. There's another code below and please check the results and choose one you want.
If you want to use reduce(into:updateAccumulatingResult:), you can write something like this.
do {
let response = try decoder.decode([UserModel].self, from: data)
let userArray: [(name: String, game: String)] = response.map {($0.name, $0.game)}
let reduction = userArray.reduce(into: [String:[String]]()) {result, element in
if !element.game.isEmpty {
result[element.name, default: []].append(element.game)
}
}
print(reduction)
} catch {
print(error)
}
If you prefer an initializer of Dictionary, this may work:
do {
let response = try decoder.decode([UserModel].self, from: data)
let userArray: [(name: String, games: [String])] = response.map {
($0.name, $0.game.isEmpty ? [] : [$0.game])
}
let reduction = Dictionary(userArray) {old, new in old + new}
print(reduction)
} catch {
print(error)
}
Both output:
["#jade": ["WoW"], "#kalel": ["WoW"]]
Anyway, your way of combining loop, Dictionary(grouping:) and reduce(into:) in addition of userDict.keys is making things too complex than they should be.
ADDITION When you want to get a Dictionary with keys as games:
do {
let response = try decoder.decode([UserModel].self, from: data)
let userArray: [(game: String, name: String)] = response.compactMap {
$0.game.isEmpty ? nil : ($0.game, $0.name)
}
let reduction = userArray.reduce(into: [String:[String]]()) {result, element in
result[element.game, default: []].append(element.name)
}
print(reduction)
} catch {
print(error)
}
Or:
do {
let response = try decoder.decode([UserModel].self, from: data)
let userArray: [(game: String, names: [String])] = response.compactMap {
$0.game.isEmpty ? nil : ($0.game, [$0.name])
}
let reduction = Dictionary(userArray) {old, new in old + new}
print(reduction)
} catch {
print(error)
}
Output:
["WoW": ["#jade", "#kalel"]]

Swift Add codable to array of codable

I looking to convert a row of SQlite to JSON array.
Example:
{
"0": {
"room_id": "5034"
},
"1": {
"room_id": "5199"
},
"2": {
"room_id": "5156"
}
}
Swift4 code:
typealias Rooms = [String: Room]
struct Room: Codable {
let roomID: String
enum CodingKeys: String, CodingKey {
case roomID = "room_id"
}
}
var rooms = [Rooms]()
for room in try (db?.prepare(isco_room_time))! {
let export: Room = Room(roomID: room[room_id])
rooms.append(export)
}
My error (on line rooms.append) :
Cannot convert value of type 'ViewController.Room' to expected argument type 'ViewController.Rooms' (aka 'Dictionary')
Why do you need this?
typealias Rooms = [String: Room]
If you want an array of Codable objects you don't need the alias
Changing
var rooms = [Rooms]()
To
var rooms = [Room]()
Will work.
Since rooms is a dictionary you shouldn't use append
for room in try (db?.prepare(isco_room_time))! {
let export: Room = Room(roomID: room[room_id])
rooms[room_id] = export
}
You can try
var counter = 0
var rooms = [String:Room]()
do {
guard let dbs = db else { return }
let res = try dbs.prepare(isco_room_time)
for room in res {
let export: Room = Room(roomID: room.id)
rooms["\(counter)"] = export
counter += 1
}
}
catch {
print(error)
}

Error in parsing JSON using codeable [duplicate]

This question already has answers here:
Can comments be used in JSON?
(58 answers)
Closed 4 years ago.
I am trying to pass some data from a JSON file using the new(ish) codeable capability in Swift. I have used the below syntax before without issue. I believe I may have something set up wrong, however, as I can't seem to understand why I keep receiving the below message when the JSON format has been approved by a JSON parser.
The error message:
error:dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))
The code in my QuestionFactory file...
class QuestionFactory {
func parseJSON(filename fileName: String) -> Quiz? {
if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
print(url)
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
print("data received is \(data.count) bytes:\n\(data)")
print(data)
print(data as NSData)
let jsonData = try decoder.decode(Quiz.self, from: data)
print(jsonData)
} catch {
print("error:\(error)")
}
}
return nil
}
}
The code in my initial ViewController:
class LaunchScreen: UIViewController {
private var quiz: Quiz?
private let jsonFileName = "QuizData"
func viewDidLoad() {
super.viewDidLoad()
createQuiz()
}
private func createQuiz() {
let questionFactory = QuestionFactory()
guard let parsedQuiz = questionFactory.parseJSON(filename: jsonFileName) else {
print("Error creating quiz")
return
}
quiz = parsedQuiz
}
func movesToMainMenuScreen() {
let transition = CATransition()
transition.duration = 1.5
transition.type = kCATransitionFade
self.navigationController?.view.layer.add(transition, forKey:nil)
let mainMenuVC: UIViewController = MainMenuViewController(quiz: quiz!) >> I am receiving an error here as well, perhaps due to my mainMenuVC's required init?
navigationController?.pushViewController(mainMenuVC, animated: false)
}
In my mainMenuViewController:
class mainMenuViewController: UIViewController {
private var quiz: Quiz! {
didSet {
tableViewAdapter = AnswerTableViewAdapter(answers: quiz.questions[0].answers) >> Although, it is not obviously reaching this far to read through the JSON.
}
required init(quiz: Quiz) {
super.init(nibName: nil, bundle: nil)
defer {
self.quiz = quiz
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The JSON looks like this...
{
"questions":[
{
"text": "1. Where will the 2022 World cup be held?",
"answers": [
{
"text": "Qatar",
"isCorrect": true,
"answerType": "2"
},
{
"text": "دولة قطر",
"isCorrect": true,
"answerType": "1"
},
{
"text": "Jamaica",
"isCorrect": false,
"answerType": "0"
},
{
"image":"qatarFlag",
"isCorrect": true,
"answerType": "3"
}
]
}]
}
The Model files....
Quiz.swift
import Foundation
struct Quiz: Decodable {
var questions: [Question]
}
Question.swift
import Foundation
struct Question: Decodable {
var text: String
var answers: [Answer]
}
Answer.swift
import Foundation
struct Answer: Decodable {
var text: String
var image: String
var isCorrect: Bool
var answerType: String
}
There is extra
]
}
added on last two lines remove these both closing brackets and try to parse JSON.
And make your model's properties to optional to avoid nullable crashes.
The Model files....
Quiz.swift
import Foundation
struct Quiz: Decodable {
var questions: [Question]?
}
Question.swift
import Foundation
struct Question: Decodable {
var text: String?
var answers: [Answer]?
}
Answer.swift
import Foundation
struct Answer: Decodable {
var text: String?
var image: String?
var isCorrect: Bool?
var answerType: String?
}

Deserialize JSON / NSDictionary to Swift objects

Is there a way to properly deserialize a JSON response to Swift objects resp. using DTOs as containers for fixed JSON APIs?
Something similar to http://james.newtonking.com/json or something like this example from Java
User user = jsonResponse.readEntity(User.class);
whereby jsonResponse.toString() is something like
{
"name": "myUser",
"email": "user#example.com",
"password": "passwordHash"
}
SWIFT 4 Update
Since you give a very simple JSON object the code prepared for to handle that model. If you need more complicated JSON models you need to improve this sample.
Your Custom Object
class Person : NSObject {
var name : String = ""
var email : String = ""
var password : String = ""
init(JSONString: String) {
super.init()
var error : NSError?
let JSONData = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let JSONDictionary: Dictionary = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &error) as NSDictionary
// Loop
for (key, value) in JSONDictionary {
let keyName = key as String
let keyValue: String = value as String
// If property exists
if (self.respondsToSelector(NSSelectorFromString(keyName))) {
self.setValue(keyValue, forKey: keyName)
}
}
// Or you can do it with using
// self.setValuesForKeysWithDictionary(JSONDictionary)
// instead of loop method above
}
}
And this is how you invoke your custom class with JSON string.
override func viewDidLoad() {
super.viewDidLoad()
let jsonString = "{ \"name\":\"myUser\", \"email\":\"user#example.com\", \"password\":\"passwordHash\" }"
var aPerson : Person = Person(JSONString: jsonString)
println(aPerson.name) // Output is "myUser"
}
I recommend that you use code generation (http://www.json4swift.com) to create native models out of the json response, this will save your time of parsing by hand and reduce the risk of errors due to mistaken keys, all elements will be accessible by model properties, this will be purely native and the models will make more sense rather checking the keys.
Your conversion will be as simple as:
let userObject = UserClass(userDictionary)
print(userObject!.name)
Swift 2: I really like the previous post of Mohacs! To make it more object oriented, i wrote a matching Extension:
extension NSObject{
convenience init(jsonStr:String) {
self.init()
if let jsonData = jsonStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
{
do {
let json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as! [String: AnyObject]
// Loop
for (key, value) in json {
let keyName = key as String
let keyValue: String = value as! String
// If property exists
if (self.respondsToSelector(NSSelectorFromString(keyName))) {
self.setValue(keyValue, forKey: keyName)
}
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
}
else
{
print("json is of wrong format!")
}
}
}
custom classes:
class Person : NSObject {
var name : String?
var email : String?
var password : String?
}
class Address : NSObject {
var city : String?
var zip : String?
}
invoking custom classes with JSON string:
var jsonString = "{ \"name\":\"myUser\", \"email\":\"user#example.com\", \"password\":\"passwordHash\" }"
let aPerson = Person(jsonStr: jsonString)
print(aPerson.name!) // Output is "myUser"
jsonString = "{ \"city\":\"Berlin\", \"zip\":\"12345\" }"
let aAddress = Address(jsonStr: jsonString)
print(aAddress.city!) // Output is "Berlin"
Yet another JSON handler I wrote:
https://github.com/dankogai/swift-json
With it you can go like this:
let obj:[String:AnyObject] = [
"array": [JSON.null, false, 0, "", [], [:]],
"object":[
"null": JSON.null,
"bool": true,
"int": 42,
"double": 3.141592653589793,
"string": "a α\t弾\n𪚲",
"array": [],
"object": [:]
],
"url":"http://blog.livedoor.com/dankogai/"
]
let json = JSON(obj)
json.toString()
json["object"]["null"].asNull // NSNull()
json["object"]["bool"].asBool // true
json["object"]["int"].asInt // 42
json["object"]["double"].asDouble // 3.141592653589793
json["object"]["string"].asString // "a α\t弾\n𪚲"
json["array"][0].asNull // NSNull()
json["array"][1].asBool // false
json["array"][2].asInt // 0
json["array"][3].asString // ""
As you see no !? needed between subscripts.
In addition to that you can apply your own schema like this:
//// schema by subclassing
class MyJSON : JSON {
override init(_ obj:AnyObject){ super.init(obj) }
override init(_ json:JSON) { super.init(json) }
var null :NSNull? { return self["null"].asNull }
var bool :Bool? { return self["bool"].asBool }
var int :Int? { return self["int"].asInt }
var double:Double? { return self["double"].asDouble }
var string:String? { return self["string"].asString }
var url: String? { return self["url"].asString }
var array :MyJSON { return MyJSON(self["array"]) }
var object:MyJSON { return MyJSON(self["object"]) }
}
let myjson = MyJSON(obj)
myjson.object.null // NSNull?
myjson.object.bool // Bool?
myjson.object.int // Int?
myjson.object.double // Double?
myjson.object.string // String?
myjson.url // String?
There's a great example by Apple for deserializing JSON with Swift 2.0
The trick is to use the guard keyword and chain the assignments like so:
init?(attributes: [String : AnyObject]) {
guard let name = attributes["name"] as? String,
let coordinates = attributes["coordinates"] as? [String: Double],
let latitude = coordinates["lat"],
let longitude = coordinates["lng"],
else {
return nil
}
self.name = name
self.coordinates = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
I personally prefer native parsing vs any 3rd party, as it is transparent and magic-less. (and bug less?)
Using quicktype, I generated your model and serialization helpers from your sample:
import Foundation
struct User: Codable {
let name: String
let email: String
let password: String
}
extension User {
static func from(json: String, using encoding: String.Encoding = .utf8) -> OtherUser? {
guard let data = json.data(using: encoding) else { return nil }
return OtherUser.from(data: data)
}
static func from(data: Data) -> OtherUser? {
let decoder = JSONDecoder()
return try? decoder.decode(OtherUser.self, from: data)
}
var jsonData: Data? {
let encoder = JSONEncoder()
return try? encoder.encode(self)
}
var jsonString: String? {
guard let data = self.jsonData else { return nil }
return String(data: data, encoding: .utf8)
}
}
Then parse User values like this:
let user = User.from(json: """{
"name": "myUser",
"email": "user#example.com",
"password": "passwordHash"
}""")!
I wrote this small open-source library recently that lets you quickly and easily deserialize dictionaries into Swift objects: https://github.com/isair/JSONHelper
Using it, deserializing data becomes as easy as this:
var myInstance = MyClass(data: jsonDictionary)
or
myInstance <-- jsonDictionary
And models need to look only like this:
struct SomeObjectType: Deserializable {
var someProperty: Int?
var someOtherProperty: AnotherObjectType?
var yetAnotherProperty: [YetAnotherObjectType]?
init(data: [String: AnyObject]) {
someProperty <-- data["some_key"]
someOtherProperty <-- data["some_other_key"]
yetAnotherProperty <-- data["yet_another_key"]
}
}
Which, in your case, would be:
struct Person: Deserializable {
var name: String?
var email: String?
var password: String?
init(data: [String: AnyObject]) {
name <-- data["name"]
email <-- data["email"]
password <-- data["password"]
}
}
If you would like parse from and to json without the need to manually map keys and fields, then you could also use EVReflection. You can then use code like:
var user:User = User(json:jsonString)
or
var jsonString:String = user.toJsonString()
The only thing you need to do is to use EVObject as your data objects base class.
See the GitHub page for more detailed sample code
I am expanding upon Mohacs and Peter Kreinz's excellent answers just a bit to cover the array of like objects case where each object contains a mixture of valid JSON data types. If the JSON data one is parsing is an array of like objects containing a mixture of JSON data types, the do loop for parsing the JSON data becomes this.
// Array of parsed objects
var parsedObjects = [ParsedObject]()
do {
let json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as [Dictionary<String, AnyObject>]
// Loop through objects
for dict in json {
// ParsedObject is a single instance of an object inside the JSON data
// Its properties are a mixture of String, Int, Double and Bool
let parsedObject = ParsedObject()
// Loop through key/values in object parsed from JSON
for (key, value) in json {
// If property exists, set the value
if (parsedObject.respondsToSelector(NSSelectorFromString(keyName))) {
// setValue can handle AnyObject when assigning property value
parsedObject.setValue(keyValue, forKey: keyName)
}
}
parsedObjects.append(parsedObject)
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
This way lets you get the user from a URL. It's parse the NSData to a NSDictionary and then to your NSObject.
let urlS = "http://api.localhost:3000/"
func getUser(username: Strung) -> User {
var user = User()
let url = NSURL(string: "\(urlS)\(username)")
if let data = NSData(contentsOfURL: url!) {
setKeysAndValues(user, dictionary: parseData(data))
}
return user
}
func setKeysAndValues (object : AnyObject, dictionary : NSDictionary) -> AnyObject {
for (key, value) in dictionary {
if let key = key as? String, let value = value as? String {
if (object.respondsToSelector(NSSelectorFromString(key))) {
object.setValue(value, forKey: key)
}
}
}
return object
}
func parseData (data : NSData) -> NSDictionary {
var error: NSError?
return NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary
}
In Swift 4, You can use the Decoding, CodingKey protocols to deserialize the JSON response:
Create the class which confirm the decodable protocol
class UserInfo: Decodable
Create members of the class
var name: String
var email: String
var password: String
Create JSON key enum which inherits from CodingKey
enum UserInfoCodingKey: String, CodingKey {
case name
case password
case emailId
}
Implement init
required init(from decoder: Decoder) throws
The whole class look like :
Call Decoder
// jsonData is JSON response and we get the userInfo object
let userInfo = try JsonDecoder().decode(UserInfo.self, from: jsonData)
You do this by using NSJSONSerialization. Where data is your JSON.
First wrap it in an if statement to provide some error handling capablity
if let data = data,
json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject] {
// Do stuff
} else {
// Do stuff
print("No Data :/")
}
then assign them:
let email = json["email"] as? String
let name = json["name"] as? String
let password = json["password"] as? String
Now, This will show you the result:
print("Found User iname: \(name) with email: \(email) and pass \(password)")
Taken from this Swift Parse JSON tutorial. You should check out the tutorial as it goes a lot more in depth and covers better error handling.