I have been searching for days to convert a fairly simple JSON string to an object type in Swift but with no avail.
Here is the code for web service call:
For iOS 10
& Swift 3
, using Alamofire & Gloss:
Alamofire.request("http://localhost:8080/category/en").responseJSON { response in
if let data = response.data {
if let categories = [Category].from(data: response.data) {
self.categories = categories
self.categoryCollectionView.reloadData()
} else {
print("Casting error")
}
} else {
print("Data is null")
}
}
and here is the Category class
import Gloss
struct Category: Decodable {
let categoryId: Int?
let name: String?
let image: String?
init?(json: JSON) {
self.categoryId = "categoryId" <~~ json
self.name = "name" <~~ json
self.image = "image" <~~ json
}
}
IMO, this is by far the most elegant solution.
Using SwiftyJSON library, you could make it like
if let path : String = Bundle.main.path(forResource: "tiles", ofType: "json") {
if let data = NSData(contentsOfFile: path) {
let optData = try? JSON(data: data as Data)
guard let json = optData else {
return
}
for (_, object) in json {
let name = object["name"].stringValue
print(name)
}
}
}
Swift 4 parses JSON much more elegantly. Just adopt the codable protocol for your structure as per this simplified example:
struct Business: Codable {
let id: Int
let name: String
}
To parse the JSON array, you tell the decoder what the objects of the data array are
let parsedData = decoder.decode([Business].self, from: data)
Here's a full working example:
import Foundation
struct Business: Codable {
let id: Int
let name: String
}
// Generating the example JSON data:
let originalObjects = [Business(id: 0, name: "A"), Business(id: 1, name: "B")]
let encoder = JSONEncoder()
let data = try! encoder.encode(originalObjects)
// Parsing the data:
let decoder = JSONDecoder()
let parsedData = try! decoder.decode([Business].self, from: data)
For more background, check out this excellent guide.
I like RDC's response, but why limit the JSON returned to have only arrays at the top level? I needed to allow a dictionary at the top level, so I modified it thus:
extension String
{
var parseJSONString: AnyObject?
{
let data = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
if let jsonData = data
{
// Will return an object or nil if JSON decoding fails
do
{
let message = try NSJSONSerialization.JSONObjectWithData(jsonData, options:.MutableContainers)
if let jsonResult = message as? NSMutableArray {
return jsonResult //Will return the json array output
} else if let jsonResult = message as? NSMutableDictionary {
return jsonResult //Will return the json dictionary output
} else {
return nil
}
}
catch let error as NSError
{
print("An error occurred: \(error)")
return nil
}
}
else
{
// Lossless conversion of the string was not possible
return nil
}
}
let jsonString = "{\"id\":123,\"Name\":\"Munish\"}"
Convert String to NSData
var data: NSData =jsonString.dataUsingEncoding(NSUTF8StringEncoding)!
var error: NSError?
Convert NSData to AnyObject
var jsonObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &error)
println("Error: \\(error)")
let id = (jsonObject as! NSDictionary)["id"] as! Int
let name = (jsonObject as! NSDictionary)["name"] as! String
println("Id: \\(id)")
println("Name: \\(name)")
Here are some tips how to begin with simple example.
Consider you have following JSON Array String (similar to yours) like:
var list:Array<Business> = []
// left only 2 fields for demo
struct Business {
var id : Int = 0
var name = ""
}
var jsonStringAsArray = "[\n" +
"{\n" +
"\"id\":72,\n" +
"\"name\":\"Batata Cremosa\",\n" +
"},\n" +
"{\n" +
"\"id\":183,\n" +
"\"name\":\"Caldeirada de Peixes\",\n" +
"},\n" +
"{\n" +
"\"id\":76,\n" +
"\"name\":\"Batata com Cebola e Ervas\",\n" +
"},\n" +
"{\n" +
"\"id\":56,\n" +
"\"name\":\"Arroz de forma\",\n" +
"}]"
// convert String to NSData
var data: NSData = jsonStringAsArray.dataUsingEncoding(NSUTF8StringEncoding)!
var error: NSError?
// convert NSData to 'AnyObject'
let anyObj: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0),
error: &error)
println("Error: \(error)")
// convert 'AnyObject' to Array<Business>
list = self.parseJson(anyObj!)
//===============
func parseJson(anyObj:AnyObject) -> Array<Business>{
var list:Array<Business> = []
if anyObj is Array<AnyObject> {
var b:Business = Business()
for json in anyObj as Array<AnyObject>{
b.name = (json["name"] as AnyObject? as? String) ?? "" // to get rid of null
b.id = (json["id"] as AnyObject? as? Int) ?? 0
list.append(b)
}// for
} // if
return list
}//func
[EDIT]
To get rid of null changed to:
b.name = (json["name"] as AnyObject? as? String) ?? ""
b.id = (json["id"] as AnyObject? as? Int) ?? 0
See also Reference of Coalescing Operator (aka ??
)
Hope it will help you to sort things out,