Swift 4 JSONSerialization.jsonObject

I am using Xcode 9.2 and Swift 4. How to check whether the returned json data is empty?
Now it gives me error if json [0] [“data”] type’Any’ has no subscript member in the line

var json: NSMutableArray = []
var newsArray: NSMutableArray = []

let url = URLFactory()
var data = try! NSData(contentsOf: url.getURL()) as Data< br />do {
json = try JSONSerialization.jsonObject(with: data, options: []) as! NSMutableArray
if json[0]["data"] {
// data is not null
}
} catch let error as NSError {
// handle error
}

My JSON returns the following content:

{
"data":
[
{
"news_id":123,
"title":"title" ,
"news_date":"2017-02-08 21:46:06",
"news_url":"url",
"short_description":"description",
"category_id":4,
"category_name":"Health",
"latlng":
[
{
"lat":"43.003429",
"lng":"-78.696335"
}
] }
{....
}

if you Using Swift 4, I might suggest using JSONDecoder:

First, define the type of 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]
< br /> // 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"< br /> case c ategoryName = "category_name"
case coordinates = "latlng"
}
}

struct Coordinate: Codable {
let lat: String
let lng: String
}

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)
}

Obviously, if your JSON is different, you may need to change your object accordingly ( For example, the weird thing is that latlng is an array of coordinates). Also, if you want to convert some of these strings to numbers, you can define a custom init(from:) method, but I would rather fix the JSON (why does latlng return a string Value instead of numeric value).

For more information, see Encoding and Decoding Custom Types.

By the way, I suggest not to use this mode (note, this is your Network request logic, but NSData is removed):

let data = try! Data(contentsOf: url.getURL()) 

This will retrieve data synchronously, which may be problematic because

>When retrieving data, the application will be frozen, resulting in a poor user experience;
>You You may face the risk of watching the watchdog process of the frozen application kill your application; and
>You do not have strong error handling, if the network request fails, it will crash.

I It is recommended to use 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 {< br /> // use `responseObject.data` to update model objects and/or UI here
}
}
task.resume()

I am using Xcode 9.2 and Swift 4. How to check whether the returned json data is empty?
Now it gives me error if json [0] [“data”] type’Any’ has no subscript member in the line

var json: NSMutableArray = []
var newsArray: NSMutableArray = []

let url = URLFactory()
var data = try! NSData(contentsOf: url.getURL()) as Data< br />do {
json = try JSONSerialization.jsonObject(with: data, options: []) as! NSMutableArray
if json[0]["data"] {
// data is not null
}
} catch let error as NSError {
// handle error
}

My JSON returns the following content:

{
"data":
[
{
"news_id":123,
"title":"title" ,
"news_date":"2017-02-08 21:46:06",
"news_url":"url",
"short_description":"description",
"category_id":4,
"category_name":"Health",
"latlng":
[
{
"lat":"43.003429",
"lng":"-78.696335"
}
]
}
{....
}

If you are using Swift 4, I might recommend JSONDecoder:

First of all, define the type to save 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
}

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)
}

Obviously, if your JSON is different, you may need to change your object accordingly (for example, the weird thing is that latlng is an array of coordinates) Also, if you want to convert some of these strings to numbers, you can define a custom init(from:) method, but I would rather fix the JSON (why latlng returns string values ​​instead of numeric values).

< p>For more information, please refer to Encoding and Decoding Custom Types.

By the way, I suggest not to use this mode (note that this is your network request logic, but NSData is removed):

let data = try! Data(contentsOf: url.getURL())

This will retrieve the data synchronously, which may be problematic because < /p>

>When retrieving data, the application will be frozen, resulting in a poor user experience;
> You may face the risk of watching the watchdog process of the frozen application kill your application; and
>You don't have strong error handling, if the network request fails, it will crash.

I recommend 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()

Leave a Comment

Your email address will not be published.