Filter Data in SwiftyJson - ios

I have one SwiftyJson object.
I can not filter that array. I have tried this solution https://stackoverflow.com/a/37497170/4831567. But my json format is different that's why not working.
[
{
"name": "19860",
"header": {
"start_time": "1519270200",
"end_time": "1519299000",
"state": "lunch"
},
"alerts": "1",
"venue": {
"location": "Delhi, India",
"timezone": "+05:30"
},
"srs_category": [
0,
1
]
},
{
"name": "19861",
"header": {
"start_time": "1519270200",
"end_time": "1519299000",
"state": "Dinner"
},
"alerts": "1",
"venue": {
"location": "Mumbai, India",
"timezone": "+05:30"
},
"srs_category": [
1,
3
]
},
{
"name": "19862",
"header": {
"start_time": "1519270200",
"end_time": "1519299000",
"state": "lunch"
},
"alerts": "1",
"venue": {
"location": "Surat, India",
"timezone": "+05:30"
},
"srs_category": [
0,
2
]
}
]
i want to find that object that srs_category contain 1. I know it is possible by looping and condition. But i want via NSPredicate. If it is possible then please help me.
Thank You.

Here is easy way to use SwiftyJSON:
let filtered = JSON(yourArray).arrayValue.filter({
$0["srs_category"].arrayValue.map({ $0.intValue }).contains(1)
})

Use a Swift native function rather than NSPredicate
data represents the Data object received from somewhere
do {
if let json = try JSONSerialization.jsonObject(with:data) as? [[String:Any]] {
let srsCategory1 = json.first(where: { dict -> Bool in
guard let array = dict["srs_category"] as? [Int] else { return false }
return array.contains(1)
})
print(srsCategory1 ?? "not found")
}
} catch {
print(error)
}
If there are multiple items which can match the condition replace first with filter. Then the result is a non-optional array.

Related

How to access indices of an NSDictionary, and convert that key’s value to an Int in Swift?

I’m trying to access indices of an NSDictionary, and convert that key’s value to an Int using Swift.
I’m also using an API to fetch data. The API response is what I’m using to create an initial dictionary out of, then I create a dictionary out of the “hours” part of the API response. The API call part of my code is working, so I’ve only included code related to accessing the hoursDictionary.
I’ve tried using [[[String: Any]]] instead of [NSDictionary] for hoursDictionary after looking up this problem online, but this did not work for me.
The error I keep getting is at the if statement line: if Int(hoursDictionary[0][5][2]) > Integer for a certain time { , and the error text is: “Value of type 'Any?' has no subscripts”. I know this is because the NSDictionary’s key’s value that I’m trying to access has a value of type Any.
I think the error is somewhere in this if statement, and is related to changing the data type of that part in the dictionary that I’m trying to access to an Int.
The API that I’m using is the Yelp Fusion API, and the API search that I’m using is “Business Details”. Here’s a link to this documentation: https://www.yelp.com/developers/documentation/v3/business .
An example of the API response body that is being returned and what I’m accessing is the following:
{
"id": "WavvLdfdP6g8aZTtbBQHTw",
"alias": "gary-danko-san-francisco",
"name": "Gary Danko",
"image_url": "https://s3-media2.fl.yelpcdn.com/bphoto/CPc91bGzKBe95aM5edjhhQ/o.jpg",
"is_claimed": true,
"is_closed": false,
"url": "https://www.yelp.com/biz/gary-danko-san-francisco?adjust_creative=wpr6gw4FnptTrk1CeT8POg&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_lookup&utm_source=wpr6gw4FnptTrk1CeT8POg",
"phone": "+14157492060",
"display_phone": "(415) 749-2060",
"review_count": 5296,
"categories": [
{
"alias": "newamerican",
"title": "American (New)"
},
{
"alias": "french",
"title": "French"
},
{
"alias": "wine_bars",
"title": "Wine Bars"
}
],
"rating": 4.5,
"location": {
"address1": "800 N Point St",
"address2": "",
"address3": "",
"city": "San Francisco",
"zip_code": "94109",
"country": "US",
"state": "CA",
"display_address": [
"800 N Point St",
"San Francisco, CA 94109"
],
"cross_streets": ""
},
"coordinates": {
"latitude": 37.80587,
"longitude": -122.42058
},
"photos": [
"https://s3-media2.fl.yelpcdn.com/bphoto/CPc91bGzKBe95aM5edjhhQ/o.jpg",
"https://s3-media4.fl.yelpcdn.com/bphoto/FmXn6cYO1Mm03UNO5cbOqw/o.jpg",
"https://s3-media4.fl.yelpcdn.com/bphoto/HZVDyYaghwPl2kVbvHuHjA/o.jpg"
],
"price": "$$$$",
"hours": [
{
"open": [
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 0
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 1
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 2
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 3
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 4
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 5
},
{
"is_overnight": false,
"start": "1730",
"end": "2200",
"day": 6
}
],
"hours_type": "REGULAR",
"is_open_now": false
}
],
"transactions": [],
"special_hours": [
{
"date": "2019-02-07",
"is_closed": null,
"start": "1600",
"end": "2000",
"is_overnight": false
}
]
}
Snippet of my code:
FetchData.swift
/// Read data as JSON
let json = try JSONSerialization.jsonObject(with: data!, options: [])
/// Main dictionary
guard let responseDictionary = json as? NSDictionary else {return}
/// Creating hours dictionary,
guard let hoursDictionary = responseDictionary.value(forKey: "hours") as? [NSDictionary] else {return}
if let endTimeAsString = hoursDictionary["open"][5]["end"] as? String,
let endTimeAsInt = Int(endTimeAsString),
endTimeAsInt > An integer representing a certain time {
// Do something
}
You can't access a dictionary's [nth] index like you would an array because a dictionary is an unordered collection. Instead you would have to do something like this [CORRECTED] hoursDictionary[0]["open"][5]["end"], or whatever sequence to get the value you need.
Or, I tend to split this up so I can ensure I am processing each step correctly like so:
guard let hoursDictionaries = responseDictionary.value(forKey: "hours") as? [NSDictionary] else {return}
if let firstHoursDictionary = hoursDictionaries[0] as? NSDictionary,
let openDictionarys = firstHoursDictionary["open"] as? [NSDictionary],
let firstOpenDictionary = openDictionarys[5] as? NSDictionary,
let endTimeAsString = firstOpenDictionary["end"] as? String,
let endTimeAsInt = Int(endTimeAsString),
endTimeAsInt > someInt {
// Do something
}
// Remember, you can always check what type the compiler is inferring something
// to be by right-clicking on the variable name and clicking `Show Quick Help`.

Fail to decode JSON response if it contains more than x-number of elements

I can successfully decode JSON from this URL, mostly. The query item -nbd is the number of "dates" to request.
https://ssp.imcce.fr/webservices/miriade/api/ephemcc.php?-step=1m&-tcoor=3&-teph=1&-observer=43.078148,-79.075699,180.0&-mime=json&-nbd=1440&-output=--iso&-ep=2021-1-17T00:00&-name=p:Sun
When I request -nbd=769 or fewer dates, ephem is correctly decoded every time.
However, when I request -nbd=770 or more dates, my dataTask prints out the entire response with 1440 elements, but ephem is nil.
What could be going wrong with this?
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
let decoder = JSONDecoder()
if let data = data {
let str = String(data: data, encoding: .utf8)!
print(str)
let ephem = try? decoder.decode(EphemCC.self, from: data)
completion(ephem)
} else {
print("Either no data was returned, or data was not properly decoded.")
completion(nil)
}
}
task.resume()
Sample JSON response:
{
"sso": {
"num": "11",
"name": "Sun",
"type": "planet",
"parameters": {
"diameter": 0.1392E+7
}
},
"coosys": {
"epoch": "J2000",
"equinox": "J2000",
"system": "eq_ICRF"
},
"ephemeris": {
"time_scale": "UTC",
"planetary_theory": "INPOP19A",
"coordinates": "local",
"reference_frame": {
"type": "astrometric J2000",
"plane": "equator",
"center": "topocenter",
"topocenter": {
"iau_code": "--1",
"name": "userLocation",
"longitude": -0.79075698999999986E+2,
"latitude": 0.43078147999999999E+2,
"altitude": 0.18E+3
}
}
},
"data": [
{
"Date": "2021-01-17T00:00:00.000",
"LAST": "02:30:14.28",
"Az": 0.26002683458818331E+3,
"H": -0.20245586021541037E+2,
"Dobs": 0.98378058040177629E+0,
"VMag": -0.26775508772817108E+2,
"R": -0.999E+3,
"RV": 0.42476667062773499E+0
},
//
// ... etc, 1440 "data" elements received
//
{
"Date": "2021-01-17T23:59:00.000",
"LAST": "02:33:10.66",
"Az": 0.25997789921032143E+3,
"H": -0.19879751688585404E+2,
"Dobs": 0.98384649280603065E+0,
"VMag": -0.26775363291013889E+2,
"R": -0.999E+3,
"RV": 0.43266153050417039E+0
}
],
"datacol": {
"Date": "Date",
"LAST": "Local sidereal time",
"Az": "Azimuth",
"H": "Elevation",
"Dobs": "Range of target center to observer",
"VMag": "Apparent magnitude",
"R": "Atmospheric refraction",
"RV": "Radial velocity of target wrt observer"
},
"unit": {
"diameter": "km",
"topocenter": {
"longitude": "deg",
"latitude": "deg",
"altitude": "m"
},
"LAST": "hms",
"Az": "deg",
"H": "deg",
"Dobs": "au",
"VMag": "mag",
"R": "arcsec",
"RV": "km/s"
}
}

How do take the values from a large JSON response with multiple arrays and brackets?

I have a JSON response (over 500lines) , that has several arrays and brackets inside. Basically an overly nested response.
I am using Alamofire for fetching and i get a JSONData as response. But I don't know how to take values from the response and print it on a custom cell .
I am using Alamofire 5 to get the JSON response.
Please excuse if this sounds too newbieish , I am new to iOS developing.
{
"availabilityResultList": [
{
"availabilityRouteList": [
{
"availabilityByDateList": [
{
"originDestinationOptionList": [
{
"fareComponentGroupList": [
{
"boundList": [
{
"availFlightSegmentList": [
{
"addOnSegment": false,
"flightSegment": {
"journeyDuration": "PT1H15M",
"distance": 1,
"departureAirport": {
"locationName": "LOC",
"cityInfo": {
"country": {
"locationName": "LOC",
"currency": {
"code": "USD"
},
"locationCode": "LOC",
"locationNameLanguage": "EN"
},
"city": {
"locationName": "LOC",
"locationCode": "LOC",
"locationNameLanguage": "EN"
}
},
"codeContext": "ASD",
"language": "EN",
"locationCode": "LOC"
},
"equipment": {
"airEquipType": "ABC",
"changeofGauge": false
},
"remark": "NO",
"ticketType": "PP",
"onTimeRate": 0,
"flightNotes": [
{
"deiCode": 0
}
],
"flightSegmentID": "",
"flownMileageQty": 0,
"flightNumber": "106",
"groundDuration": "",
"trafficRestriction": {
"code": "",
"explanation": {}
},
"stopQuantity": 0,
"codeshare": false,
"secureFlightDataRequired": false,
"departureDateTime": {
"month": 5,
"hour": 6,
"year": 2019,
"timezone": 270,
"day": 6,
"minute": 45,
"second": 0
},
"ondControlled": false,
"arrivalDateTime": {
"month": 5,
"hour": 8,
"year": 2019,
"timezone": 270,
"day": 6,
"minute": 0,
"second": 0
},
"airline": {
"code": "RQ"
},
"arrivalAirport": {
"locationName": "LOC",
"cityInfo": {
"country": {
"locationName": "AA",
"currency": {
"code": "USD"
},
"locationCode": "AA",
"locationNameLanguage": "EN"
},
"city": {
"locationName": "loc",
"locationCode": "LOC",
"locationNameLanguage": "EN"
}
},
"codeContext": "ASD",
"language": "EN",
"locationCode": "LOC"
},
"sector": "ASD",
"accumulatedDuration": ""
},
"marriageGroup": "-1"
}
],
"boundCode": "Outbound"
}
]
}
]
},
JSON is a very simple format and easy to read. There are only two different collection types and four value types.
{} is a dictionary and is subscripted by key
[] is an array and is subscripted by index (zero-based)
Everything in double quotes is String, even "123" and "false"
false and true is Bool
Numeric values are Double, without fractional digits Int
<null> is NSNull
With SwiftyJSON you get distance in flightSegment with (root represents the top level object`)
root["availabilityResultList"][0]["availabilityRouteList"][0]["availabilityByDateList"][0]["originDestinationOptionList"][0]["fareComponentGroupList"][0]["boundList"][0]["availFlightSegmentList"][0]["flightSegment"]["distance"]

How to send JSON response to another view in Swift 3

I have a problem with sending a JSON response from UITableView into another UITableView.
I want to send the Products array like in the code below into another UITableViewController based on the selected row on the TableView, but when I log the value in didSelectRowAt it returns nil.
So here's the JSON return.
{
"error_description": [],
"results": [
{
"id": 2,
"name": "Ernser, Kilback and Kreiger LLC",
"address": "48788 Adaline Ville 7634 Bertram Shoal",
"contact_person": "Coralie Schaden",
"mobile_number": "(238) 076-0562",
"image": {
"url": null,
"thumb": {
"url": null
},
"medium": {
"url": null
},
"small": {
"url": null
},
"icon": {
"url": null
}
},
"registered_at": "2017-01-10T04:16:52.621Z",
"products": [
{
"id": 21,
"name": "Fantastic Rubber Car",
"image": {
"url": null,
"thumb": {
"url": null
},
"medium": {
"url": null
},
"small": {
"url": null
},
"icon": {
"url": null
}
},
"points": 0,
"merchant_id": 2,
"created_at": "2017-01-10T04:16:52.630Z",
"updated_at": "2017-01-10T04:16:52.636Z"
},
{
"id": 22,
"name": "Mediocre Plastic Shirt",
"image": {
"url": null,
"thumb": {
"url": null
},
"medium": {
"url": null
},
"small": {
"url": null
},
"icon": {
"url": null
}
},
"points": 15,
"merchant_id": 2,
"created_at": "2017-01-10T04:16:52.819Z",
"updated_at": "2017-01-10T04:16:52.827Z"
},
]
}
This is a part of my code for getting the response.
I used the Alamofire
var merchantModel: Merchant!
var merchantArr = [Merchant]()
var productArr = [Product]()
var productModel : Product?
.....
case .success:
let json = JSON(data: response.data!)
for result in json["results"].arrayValue{
guard let merchantID = result["id"].number, let merchantName = result["name"].string, let merchantAddress = result["address"].string, let contactPerson = result["contact_person"].string, let mobilenumber = result["mobile_number"].string else{
return
}
self.merchantModel = Merchant(merchantID: merchantID, merchantName: merchantName, merchantAddress: merchantAddress, contactPerson: contactPerson, mobileNumber: mobilenumber, merchantImage: contactPerson)
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(self.merchantModel!, toFile: Merchant.ArchiveURL.path)
if !isSuccessfulSave {
print("Failed to save sender...")
}
for prodArr in result["products"].arrayValue{
print("prodArr:\(prodArr)")
guard let prodID = prodArr["id"].number, let prodName = prodArr["name"].string,
let points = prodArr["points"].number else{
return
}
self.productModel = Product(productID: prodID, productName: prodName, productPoints: points)
}
self.merchantArr.append(self.merchantModel!)
self.productArr.append(self.productModel!)
self.merchantModel.loadMerchant()
self.tableView.reloadData()
}
Swift is not javascript, and JSON is not the simplest way to handle the data in this language.
You'd probably prefer to transform your JSON data into Foundation objects, manipulate them, create UITableView with them... And when you'll need to have the JSON format again, you transform those Foundation objects back to JSON.
There are a lot of ways to achieve that, and some amazing third-party libraries to do it very easily. However for a start I encourage you to have a look at Apple's resources :
NSJSONSerialization
Working with JSON in Swift

Data conversion from JSON results as NSDictionary[] throws EXC_BAD_INSTRUCTION runtime error

I have the following JSON being received in my Swift code, after being parsed as a NSDictionary. In my function I am trying to extract the JSON objects in "results" block as NSDIctionary[], but this is throwing a run-time error. I don't understand why, as this was working just a few days earlier.
{
"results": [
{
"id": "3",
"name": "The National",
"slug": "thenational",
"facebook_url": "https://www.facebook.com/thenationalofficial/",
"twitter_url": "https://twitter.com/The_National",
"profile_image": "http://example.staging.com/media/profile_image/thumbnail_263x263/1352756032.jpg",
"_type": "artist",
"resource_uris": {
}
},
{
"id": "5",
"name": "Mayer Hawthorne",
"slug": "mayerhawthorne",
"facebook_url": "https://www.facebook.com/MayerHawthorne",
"twitter_url": "https://twitter.com/MayerHawthorne",
"profile_image": "http://example.example.com/media/profile_image/thumbnail_263x263/1352755133.png",
"_type": "artist",
"resource_uris": {
}
},
{
"id": "20",
"name": "I Play Maracas",
"slug": "iplaymaracas",
"facebook_url": "",
"twitter_url": "",
"profile_image": "http://staging.wedemand.com/images/en/img-list-home.gif",
"_type": "artist",
"resource_uris": {
"_demanded_by": null,
"demand_url": "http://ec2-54-86-17-163.compute-1.amazonaws.com/artists/20/?demand=1&access_token={}",
"dismiss_url": "http://ec2-54-86-17-163.compute-1.amazonaws.com/artists/20/?demand=0&access_token={}"
}
},
{
"id": "35",
"name": "Black SuperHeros",
"slug": "blacksuperheros",
"facebook_url": "",
"twitter_url": "",
"profile_image": "http://staging.example.com/images/en/img-list-home.gif",
"_type": "artist",
"resource_uris": {
}
},
{
"id": "49",
"name": "Ayman Elgadi",
"slug": "aymanelgadi",
"facebook_url": "",
"twitter_url": "",
"profile_image": "http://staging.example.com/images/en/img-list-home.gif",
"_type": "artist",
"resource_uris": {
}
},
{
"id": "8874",
"name": "Lauri",
"slug": "lauri",
"facebook_url": "http://www.facebook.com/hughlaurieblues",
"twitter_url": "http://twitter.com/hughlaurieblues",
"profile_image": "http://staging.example.com/media/profile_image/thumbnail_263x263/lauri_profilepic.jpg",
"_type": "artist",
"resource_uris": {
}
}
]
}
My IOS-Swift code receives the NSDictionary object after being parsed by AFNetworking lib and passes to the function which casts the results array as NSDictionary[], is now throwing run-time error, while earlier this was working.
(operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in println("JSON: " + responseObject.description)
var jsonResult: NSDictionary = responseObject as NSDictionary
this jsonResult is passed to the function below which tries to cast as NSDictionary[]
let allResults: NSDictionary[] = results["results"] as NSDictionary[]
UPDATE:
I printed the class of the results object as it is being returned as __NSCFDictionary.
Here What is an NSCFDictionary? is a discussion regarding this and says to use this just like NSDictionary, but in my case its not working.
The value of results is not a dictionary in your JSON, it is an array. You should get it with something like this;
let allResults: NSArray = results["results"] as NSArray

Resources