How to parse Array of JSON to array in Swift
var peoplesArray:[Any] = [
[
"People": [
"Jack",
"Jones",
"Rock",
"Taylor",
"Rob"
]
],
[
"People": [
"Rose",
"John"
]
],
[
"People": [
"Ted"
]
]
]
var finalArray:[Any] = []
for peopleDict in peoplesArray {
if let dict = peopleDict as? [String: Any], let peopleArray = dict["People"] as? [String] {
finalArray.append(peopleArray)
}
}
print(finalArray)
output:
[["Jack", "Jones", "Rock", "Taylor", "Rob"], ["Rose", "John"], ["Ted"]]
In your case, it will be:
if let path = Bundle.main.path(forResource: "People", ofType: "json") {
let peoplesArray = try! JSONSerialization.jsonObject(with: Data(contentsOf: URL(fileURLWithPath: path)), options: JSONSerialization.ReadingOptions()) as? [Any]
var finalArray:[Any] = []
for peopleDict in peoplesArray {
if let dict = peopleDict as? [String: Any], let peopleArray = dict["People"] as? [String] {
finalArray.append(peopleArray)
}
}
print(finalArray)
}
Parsing JSON array in Swift with array root object
The issue there is that you are trying to decode a dictionary instead of an array.
Just change
let postSet = try decoder.decode(DataSet.self, from: Data(dataString.utf8))
to
let postSet = try decoder.decode([SinglePost].self, from: Data(dataString.utf8))
edit/update:
Regarding your method signature just change it to return an array instead of a DataSet structure and I would return the error instead of a Bool:
static func getPost(completion: @escaping ([SinglePost]?, Error?) -> ()) {
let session = URLSession.shared
let decoder = JSONDecoder()
if let url = URL(string: serverUrl + "/post/") {
let task = session.dataTask(with: url) { data, response, error in
guard let data = data else {
completion(nil, error)
return
}
do {
completion(try decoder.decode([SinglePost].self, from: data), nil)
} catch {
print("Error Decoding JSON", error)
completion(nil, error)
}
}
task.resume()
}
}
Usage:
getPost { posts, error in
guard let posts = posts else {
print(error ?? "")
}
for post in posts {
print(post)
}
}
How to parse json in swift 4 an array inside an array
The value for key StatusList
is a dictionary, please note the {}
, the array is the value for key Details
in statusList
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any],
let statusList = parsedData["StatusList"] as? [String:Any],
let details = statusList["Details"] as? [[String:Any]] {
for detail in details {
print(detail["Pro"])
}
}
}
And don't do things like (... as? ...)!
, never!
The corresponding Codable
structs are
struct Status: Codable {
let mobileAPIError: String
let statusList: StatusList
enum CodingKeys: String, CodingKey { case mobileAPIError = "MobileAPIError", statusList = "StatusList" }
}
struct StatusList: Codable {
let errorMessage: String
let details: [Detail]
enum CodingKeys: String, CodingKey { case errorMessage = "ErrorMessage", details = "Details" }
}
struct Detail: Codable {
let pro, blNumber, referenceNumber, scac: String
let carrier, shipperCode, shipperName, shipperCity: String
let shipperState: String
enum CodingKeys: String, CodingKey {
case pro = "Pro", blNumber = "BlNumber", referenceNumber = "ReferenceNumber"
case scac = "Scac", carrier = "Carrier", shipperCode = "ShipperCode"
case shipperName = "ShipperName", shipperCity = "ShipperCity", shipperState = "ShipperState"
}
}
do {
let result = try JSONDecoder().decode(Status.self, from: data!)
print(result)
} catch { print(error) }
How to convert JSON array objects into list array | Swift 5
First of all please name structs and classes always with starting uppercase letter and declare the struct members non-optional if the API sends consistent data
struct TestStructure: Decodable {
let name: String
let orderid: Int
let trialid: Int
}
Second of all the decoding line doesn't compile, you have to write
let nav = try JSONDecoder().decode([TestStructure].self, from: data)
To get an array of all trialid
values just map
it
let allTrialids = nav.map(\.trialid)
Update: Take the compiler's advice and add explicit type to disambiguate
self.viewControllers = nav.map { test -> UIViewController in
let selected = UIImage(named: "Tab4_Large")!
let normal = UIImage(named: "Tab4_Large")!
let controller = storyboard!.instantiateViewController(withIdentifier: String(test.trialid))
controller.view.backgroundColor = UIColor.white
controller.floatingTabItem = FloatingTabItem(selectedImage: selected, normalImage: normal)
return controller
}
Decode json array as an object in swift
First, I assume you'd really like the final result to be [Product]
where Product looks like this:
struct Product {
var name: String = ""
var quantity: Int = 0
}
So if any keys are missing, they'll get the defaults. You could change this solution to throw an error in that case, but I think this approach is much nicer than Optionals.
Given that, here's how you decode it:
extension Product: Decodable {
init(from decoder: Decoder) throws {
// This is a very uniform type (all Strings). Swift can decode that
// without much help.
let container = try decoder
.singleValueContainer()
.decode([String: [[String: String]]].self)
// Extract the Products. Throwing an error here might be nicer.
let keyValues = container["Product"] ?? []
// This loops over every Key-Value element, and then loops through
// each one. We only expect one element in the second loop, though.
for keyValue in keyValues {
for (key, value) in keyValue {
switch key {
case "Name": self.name = value
case "Quantity": self.quantity = Int(value) ?? 0
default: break // Ignore unknown keys
}
}
}
// This solution just assigns defaults for missing keys, but
// you could validate that everything was found, and throw an
// error here if desired.
}
}
let data = try JSONDecoder().decode([Product].self, from: jsonData)
// [{name "exampleName", quantity 1}]
data.first!.name
// "exampleName"
In most cases the above is probably fine, but it's also very sloppy about malformed data. It just returns a default object, which could make an error very hard to track down. This example goes in the other direction, and does all the error checking you would expect from a normal Decodable.
First, we'll need a CodingKey that can accept any String. I really don't understand why this isn't built into stdlib:
struct AnyStringKey: CodingKey, Hashable, ExpressibleByStringLiteral {
var stringValue: String
init(stringValue: String) { self.stringValue = stringValue }
init(_ stringValue: String) { self.init(stringValue: stringValue) }
var intValue: Int?
init?(intValue: Int) { return nil }
init(stringLiteral value: String) { self.init(value) }
}
I also find DecodingErrors very cumbersome to build, so I often build little helper functions:
func keyNotFound(_ key: String, codingPath: [CodingKey]) -> Error {
DecodingError.keyNotFound(AnyStringKey(key),
.init(codingPath: [],
debugDescription: "\(key) key not found"))
}
func typeMismatch(_ key: String, expected: Any.Type, codingPath: [CodingKey]) -> Error {
DecodingError.typeMismatch(expected, .init(codingPath: codingPath + [AnyStringKey(key)],
debugDescription: "Expected \(expected)."))
}
With those in place, here's a more strict decoder:
extension Product: Decodable {
init(from decoder: Decoder) throws {
// This is a very uniform type (all Strings). Swift can decode that
// without much help.
let container = try decoder
.singleValueContainer()
.decode([String: [[String: String]]].self)
var codingPath: [AnyStringKey] = []
// Extract the Products. Throwing an error here might be nicer.
guard let keyValues = container["Product"] else {
throw keyNotFound("Product", codingPath: codingPath)
}
codingPath.append("Product")
var name: String?
var quantity: Int?
// This loops over every Key-Value element, and then loops through
// each one. We only expect one element in the second loop, though.
for keyValue in keyValues {
for (key, value) in keyValue {
switch key {
case "Name":
name = value
case "Quantity":
guard let intValue = Int(value) else {
throw typeMismatch("Quantity",
expected: Int.self,
codingPath: codingPath)
}
quantity = intValue
default: break // Ignore unknown keys
}
}
}
guard let name = name else {
throw keyNotFound("Name", codingPath: codingPath)
}
self.name = name
guard let quantity = quantity else {
throw keyNotFound("Quantity", codingPath: codingPath)
}
self.quantity = quantity
}
}
How to parse array of strings in swift?
If you're getting the 3840 error, then the JSON is not valid JSON, period.
The JSON string equivalent of the array is supposed to be
let jsonString = "[\"one\",\"two\",\"three\"]"
The Swift 4 literal multiline syntax shows the actual format without the escaping backslashes
let jsonString = """
["one","two","three"]
"""
You are able to parse it without any options (no .allowFragments, and no .mutableContainers)
let data = Data(jsonString.utf8)
do {
let array = try JSONSerialization.jsonObject(with: data) as! [String]
print(array) // ["one", "two", "three"]
} catch {
print(error)
}
Almost everybody misuses the JSONSerialization Reading Options
- .allowFragments is only needed if the root object is not array and not dictionary
- .mutableContainers is completely meaningless in Swift
In 99% of the cases you can omit the options
parameter
How can i parse an Json array of a list of different object using Codable?
A reasonable solution is an enum with associated values because the type can be determined by the productype
key. The init
method first decodes the productype
with a CodingKey
then in a switch
it decodes (from a singleValueContainer
) and associates the proper type/value to the corresponding case.
enum ProductType: String, Codable {
case a, b, c
}
struct Root : Codable {
let items : [Product]
}
struct ProductA : Codable {
let id, name: String
let productype: ProductType
let propertyOfA : String
}
struct ProductB : Codable {
let id, name: String
let productype: ProductType
let propertyOfB : String
}
struct ProductC : Codable {
let id, name: String
let productype: ProductType
let propertyOfC, propertyOfC2 : String
}
enum Product : Codable {
case a(ProductA), b(ProductB), c(ProductC)
enum CodingKeys : String, CodingKey { case productype }
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(ProductType.self, forKey: .productype)
let singleContainer = try decoder.singleValueContainer()
switch type {
case .a : self = .a(try singleContainer.decode(ProductA.self))
case .b : self = .b(try singleContainer.decode(ProductB.self))
case .c : self = .c(try singleContainer.decode(ProductC.self))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .a(let productA): try container.encode(productA)
case .b(let productB): try container.encode(productB)
case .c(let productC): try container.encode(productC)
}
}
}
And decode
let jsonString = """
{
"items": [
{
"id": "1",
"name": "name",
"propertyOfA": "1243",
"productype": "a"
},
{
"id": "2",
"name": "name",
"propertyOfA": "12",
"productype": "a"
},
{
"id": "3",
"name": "name",
"propertyOfA": "1243",
"productype": "a"
},
{
"id": "1",
"name": "name",
"propertyOfB": "1243",
"productype": "b"
},
{
"id": "1",
"name": "name",
"propertyOfC": "1243",
"propertyOfC2": "1243",
"productype": "c"
}
]
}
"""
do {
let result = try JSONDecoder().decode(Root.self, from: Data(jsonString.utf8))
print(result)
} catch { print(error)}
To read the enum values use also a switch
.
Related Topics
Submitting iOS App to App Store Application Identifier Invalid
Get Version Number of iOS Universal Framework in Client
How to Get the Active Processes Running in iOS
"Could Not Inspect Application Package" Xcode
Flutter iOS Build Failure Error with Multiple Commands After the Xcode Upgrade
Member Operator '%' Must Have at Least One Argument of Type 'Viewcontroller'
How to Dynamically Add Rows to a Specific Uitableview Section
Uitextview Text Selection and Highlight Jumping in iOS 8
Codesign Returned Errsecinternalcomponent in High Sierra
How to Prevent a Remote Notification from Being Displayed
How to Get 18-Digit Current Timestamp in Swift
Apple Watch - Only Getting Data If App on Phone Is Active
Filter Array by First Letter of String Property
Calling a Method at Specific Time Every Day
How to Get Touchid Information and Compare to a Fingerprint Database
Alamofire 5: Value of Type 'Result<Data, Aferror>' Has No Member 'Value'