Swift 4 JSONSerialization.jsonObject
If you're using Swift 4, I might suggest JSONDecoder
:
First, define the types to hold the parsed data:
struct ResponseObject: Codable {
let data: [NewsItem]
}
struct NewsItem: Codable {
let newsId: Int
let title: String
let newsDate: Date
let newsURL: URL
let shortDescription: String
let categoryID: Int
let categoryName: String
let coordinates: [Coordinate]
// because your json keys don't follow normal Swift naming convention, use CodingKeys to map these property names to JSON keys
enum CodingKeys: String, CodingKey {
case newsId = "news_id"
case title
case newsDate = "news_date"
case newsURL = "news_url"
case shortDescription = "short_description"
case categoryID = "category_id"
case categoryName = "category_name"
case coordinates = "latlng"
}
}
struct Coordinate: Codable {
let lat: String
let lng: String
}
And then you can parse it:
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
do {
let responseObject = try decoder.decode(ResponseObject.self, from: data)
print(responseObject.data)
} catch {
print(error)
}
Clearly, if your JSON is different, you might need to change your objects accordingly (e.g. it struck me odd that latlng
was an array of coordinates). Also, you can define custom init(from:)
methods if you want to convert some of these strings into numbers, but I'd rather fix the JSON, instead (why are latlng
returning string values rather than numeric values).
For more information, see Encoding and Decoding Custom Types.
As an aside, I'd advise against this pattern (note, this is your network request logic, but excised of NSData
):
let data = try! Data(contentsOf: url.getURL())
That will retrieve the data synchronously, which can be problematic because
- the app will be frozen while the data is being retrieved resulting in a poor UX;
- you risk having your app killed by the watchdog process which looks for frozen apps; and
- you don't have robust error handling and this will crash if the network request fails.
I'd suggest using URLSession
:
let task = URLSession.shared.dataTask(with: url.getURL()) { data, _, error in
guard let data = data, error == nil else {
print(error ?? "Unknown error")
return
}
// now parse `data` like shown above
// if you then need to update UI or model objects, dispatch that back
// to the main queue:
DispatchQueue.main.async {
// use `responseObject.data` to update model objects and/or UI here
}
}
task.resume()
Swift : JSONSerialization.jsonObject not working for json into json
Using as! [String:String]
you are saying that all values in the dictionary will be of String type, but the nested JSON related to the state key is obviously not a String
use as? [String: Any]
and then cast your other properties as needed. result["error"] as String
Using this method it makes getting the nested data more difficult than it needs to be:
if let state = result["state"] as? [String: String] {
let name = state["name"]
let value = state["value"]
}
Notes
- When using Swift 4 or greater you should be using the Codable Protocol
- You should not be force unwrapping, use conditional unwrapping (
as? [String: Any]
)
EDIT:
An example of how you can do this using Codable and how it is used.
Playground code
// you dont need this part, I am not making network request
let jsonData = """
{"error":"true","message":"no","state":{"id":"1","name":"empty"}}
""".data(using: .utf8)
struct ErrorState: Codable
{
let id: String
let name: String
}
struct ErrorResponse: Codable
{
let error: String
let message: String
let state: ErrorState
}
guard let data = jsonData else { fatalError() }
let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: data)
print(errorResponse?.state.name)
Swift JSONSerialization.jsonObject Error
The jsonObject
function will return a value of type Any
but the jsonArray
's type of NSMutableArray
. And this function will throw an error if something is wrong, put a try
keyword before it. In my experience, let change the type of jsonArray
to array of dictionary, so you will extract data with ease.
do {
let data: Data = try Data(contentsOf: url as URL)
let jsonArray: [[String: AnyObject]] = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [[String: AnyObject]]
print("json: \(jsonArray)")
for dict in jsonArray {
let dataName = dict["dataName"] as! String
print("dataName: \(dataName)")
}
}
catch {
print("Error: (data: contentsOf: url)")
}
Swift - JSONSerialization invalid JSON
As @RobNapier pointed out I needed FHIRModels
, from Apple. I'm able to get data more easily than using a messy Codable
data approach manually.
import ModelsR4
let resource = try decoder.decode(Immunization.self, from: data)
print output is proper
28581000087106
28581000087106
Getting value from JSONSerialization key Swift
Forget JSONSerialization
and use Decodable
with JSONDecoder
:
struct DataModel: Decodable {
let id: String
let pedId: String?
let ownerId: String?
let locationId: String?
let status: String
}
do {
let dataModel = try JSONDecoder().decode(DataModel.self, from: data)
print("Status: \(dataModel.status)")
} catch ...
If you want to use JSONSerialization
, note that status
is not a dictionary, it's a String
:
if let dictionary = jsonData as? [String: Any] {
if let status = dictionary["status"] as? String {
print("Status: \(status)")
}
}
Related Topics
Function Builder Not Working When Only One Value
How to Access Content View's Elements Later in Swiftui
iOS 13.1 Cannot Save File to App Directory
Resulting Mtltexture Lighter Than Cgimage
How to Add a Move Back to User Location Button in Swiftui
How to Read Id3 Tags/Other Metadata from an Hls Stream in Swift/Avkit
Changing The Color of a Button in Swiftui on Tvos
Swiftui Reorder List Dynamic Sections from Another View
Read Static Property from Object
Play Sound with a Little Delay
Can't Use In/Contains Operator with Collection'
How to Convert Bytes to Nsstring After Aes Cryptoswift Cipher
Could Not Find a Storyboard Named 'Maintabcontroller' in Bundle Nsbundle
Supportedinterfaceorientationsforwindow in Swift 2.0
Draw a Straight Line in Swift 3 and Core Graphics
Swift 3 - Pass Struct by Reference via Unsafemutablerawpointer