Fetch and Check internal (Local) JSON file in swift - ios

I want to check city name From local JSON if found then massage show "You got it". But one problem came occurred that is I fetch data from file is successfully but I'd know how to compare it.
Here is my JSON file look like:
{
"data": [
{
"zip_code": 55001,
"latitude": 44.90717,
"longitude": -92.816193,
"city": "Afton",
"state": "MN",
"county": "Washington"
},
{
"zip_code": 55002,
"latitude": 45.513447,
"longitude": -92.894239,
"city": "Almelund",
"state": "MN",
"county": "Chisago"
}
]
}
Code is here:
func FatchingInformation(){
do {
if let file = Bundle.main.url(forResource: "Zone", withExtension: "json") {
let data = try Data(contentsOf: file)
let json = try JSONSerialization.jsonObject(with: data, options: [])
if let object = json as? [String: Any] {
// This condition work and Get JSON on Debug Area
print("Obj is ::: \(object)")
} else if let object = json as? [Any] {
// json is an array
print("Object is \(object)")
} else {
print("JSON is invalid")
}
} else {
print("no file")
}
} catch {
print(error.localizedDescription)
}
}

you are in right way on your JSON is dict of array of dictionary, you need to iterate your [String: Any] first there after check it contains array or dict then you need to follow as below
if let object = json as? [String: Any], let objectArray = object["data"] as? [[String: Any]] {
// do stuff
for getDictItems in objectArray{
if let getCityCompare = getDictItems["city"] as? String, !getCityCompare.isEmpty, getCityCompare == "Almelund"{
print("city name is \(getCityCompare)")
break
}
}
}

You ca use decodable Struct to decode json
// MARK: - Address
struct Address: Codable {
let data: [Datum]
}
// MARK: - Datum
struct Datum: Codable {
let zipCode: Int
let latitude, longitude: Double
let city, state, county: String
enum CodingKeys: String, CodingKey {
case zipCode = "zip_code"
case latitude, longitude, city, state, county
}
}
let address = try? JSONDecoder().decode(Address.self, from: jsonData)

Related

Swift: Convert object to Dictionary not working properly

I'm trying to convert an object to NSDictionary with an extension. It works fine but if the object contains an array, then the array does not convert to NSDictionary but to Json and that is not what I want. Because I try with this Dictionary to make a request post and the body accepts [String: Any].
My code:
struct Country: Codable {
let name: String
let cities: [City]
struct City: Codable {
let name: String
}
}
extension NSDictionary {
func encode<T>(_ value: T) throws -> [String: Any]? where T: Encodable {
guard let jsonData = try? JSONEncoder().encode(value) else { return nil }
return try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as? [String: Any]
}
}
Using:
let country = Country(name: "France", cities: [Country.City(name: "Paris"), Country.City(name: "Marseille")])
print(try! NSDictionary().encode(country))
Output:
["name": France, "cities": <__NSArrayI 0x600002926e60>(
{
name: "Paris",
},
{
name: "Marseille",
})
]
Expected output (what I want):
["name": France, "cities": [
[
"name": Paris,
],
[
"name": Marseille,
]
]
]
The output is correct since your result is NSDictionary and the output is the string representation (aka description) of NSDictionary. <__NSArrayI 0x600002926e60> is syntactic sugar.
By the way the expected output is invalid because the city names must be in double quotes.
The extension of NSDictionary makes no sense anyway. If you want to be able to call the method from everywhere declare a struct with a static method.
This is a swiftier version of your code. No allowFragments and all errors are thrown rather than being ignored.
struct DictionaryEncoder {
static func encode<T>(_ value: T) throws -> [String: Any] where T: Encodable {
let jsonData = try JSONEncoder().encode(value)
return try JSONSerialization.jsonObject(with: jsonData) as? [String: Any] ?? [:]
}
}
Copy the method and your structs into a Playground and run
let country = Country(name: "France", cities: [Country.City(name: "Paris"), Country.City(name: "Marseille")])
try! DictionaryEncoder.encode(country)
Don't print the result, look at the result area in the Playground, the output is exactly what you want.
You need
let res = try! JSONEncoder().encode(country)
print(res.prettyPrintedJSONString!)
extension Data {
var prettyPrintedJSONString: NSString? { /// NSString gives us a nice sanitized debugDescription
guard let object = try? JSONSerialization.jsonObject(with: self, options: []),
let data = try? JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted]),
let prettyPrintedString = NSString(data: data, encoding: String.Encoding.utf8.rawValue) else { return nil }
return prettyPrintedString
}
}
Result
{
"name" : "France",
"cities" : [
{
"name" : "Paris"
},
{
"name" : "Marseille"
}
]
}

How can I decode JSON with array and more JSON inside?

I recently began with swift. I need decode the json on below.
The JSON has inside two more JSON the first one (validation) does not matter. The second one (result) has a JSON array inside (serviceCenter). I need the information of each servicenter. I try to use servicecenter as decodeable class to get a servicenter object, but as the JSON does not have the proper format I can't do it.
[
{
"validation": {
"bValid": true,
"sDescription": "Access true."
}
},
{
"result": {
"serviceCenter": [
{
"model": "Vanquish",
"color": "Purple",
"make": "Aston Martin",
"sTag": "3666",
"sVin": "6JDO2345",
"sMiles": "3666",
"bDamage": "1",
"dDateTime": "04-17-2018 9:38 AM"
},
{
"model": "F360",
"color": "Red",
"make": "Ferrari",
"sTag": "0010",
"sVin": "6JDO2347",
"sMiles": "80000",
"bDamage": "1",
"dDateTime": "04-17-2018 9:25 AM"
},
{
"model": "Vanquish",
"color": "Purple",
"make": "Aston Martin",
"sTag": "0009",
"sVin": "6JDO2345",
"sMiles": "25000",
"bDamage": "1",
"dDateTime": "04-17-2018 9:23 AM"
},
{
"model": "Vanquish",
"color": "Purple",
"make": "Aston Martin",
"sTag": "0003",
"sVin": "6JDO2345",
"sMiles": "20000",
"bDamage": "1",
"dDateTime": "04-12-2018 10:37 AM"
}
]
}
}
]
I try so much but i cant do it.
This its my code now, Could someone help me please
do {
let parseoDatos = try JSONSerialization.jsonObject(with: data!) as! [AnyObject]
let h = type(of: parseoDatos )
print("'\(parseoDatos)' of type '\(h)'")
let contenido = parseoDatos[1]["result"]
if let services = contenido!! as? Dictionary<String, Array<Any>> {
for (_,serviceArray) in services {
for sc in serviceArray{
let h = type(of: sc )
print("'\(sc)' of type '\(h)'")
}
}
}
} catch {
print("json processing failed")
}
the result of print sc is
{
bDamage = 1;
color = Purple;
dDateTime = "04-17-2018 9:38 AM";
make = "Aston Martin";
model = Vanquish;
sMiles = 3666;
sTag = 3666;
sVin = 6JDO2345;
}' of type '__NSDictionaryI'
You can use Codable
Initial response have array of InitialElement and InitialElement is is struct with validation , result , result may be nil
don't forget to add your URL at url
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if let initial = try? JSONDecoder().decode([InitialElement].self, from: data){
// inital now have array of InitialElement and InitialElement is is struct with validation , result , result may be nil
print(initial)
}
}.resume()
With this Model for Data:
import Foundation
struct InitialElement: Codable {
let validation: Validation?
let result: ResultData?
}
struct ResultData: Codable {
let serviceCenter: [ServiceCenter]
}
struct ServiceCenter: Codable {
let model, color, make, sTag: String
let sVin, sMiles, bDamage, dDateTime: String
}
struct Validation: Codable {
let bValid: Bool
let sDescription: String
}
extension InitialElement {
init(data: Data) throws {
self = try JSONDecoder().decode(InitialElement.self, from: data)
}
}
try this code
enum ParsingError: Error {
case wrongFormat(String)
}
do {
let jsonObject = try JSONSerialization.jsonObject(with: data!)
guard let array = jsonObject as? [Any] else {
throw ParsingError.wrongFormat("wrong root object")
}
guard array.count == 2 else {
throw ParsingError.wrongFormat("array count != 2")
}
guard let dict = array[1] as? [String: Any] else {
throw ParsingError.wrongFormat("can't parse dict from array")
}
guard let serviceCenters = (dict["result"] as? [String: Any])?["serviceCenter"] else {
throw ParsingError.wrongFormat("can't parse serviceCenters")
}
guard let serviceCentersArray = serviceCenters as? [[String : Any]] else {
throw ParsingError.wrongFormat("serviceCenters is not an array")
}
print("\(type(of: serviceCentersArray))\n", serviceCentersArray)
} catch {
print("json processing failed: \(error)")
}
Thanks all for yours answers, it's my first question here, and i feels great all the help. Finally i can resolve the problem. Maybe not the best way, but here its the code:
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil{
print("error=\(String(describing: error))")
return
}
do {
let parseoDatos = try JSONSerialization.jsonObject(with: data!) as! [AnyObject]
let h = type(of: parseoDatos )
print("'\(parseoDatos)' of type '\(h)'")
let contenido = parseoDatos[1]["result"]
if let services = contenido!! as? Dictionary<String, Array<Any>> {
for (_,serviceArray) in services {
for sc in serviceArray{
let h = type(of: sc )
print("'\(sc)' of type '\(h)'")
let valid = JSONSerialization.isValidJSONObject(sc) // true
print(valid)
do {
let jsonData = try JSONSerialization.data(withJSONObject: sc, options: .prettyPrinted)
let serviceDecoded = try JSONSerialization.jsonObject(with: jsonData, options: [])
if let scJSON = serviceDecoded as? [String:String] {
print ("--------------------------")
print("'\(scJSON)' of type '\(type(of: scJSON))'")
print ("--------------------------")
}
} catch {
print(error.localizedDescription)
}
i think later y try to use Codable as suggested, but for now the code is working ok. Thanks again!
//try this it is working
let arrayMain=try?JSONSerialization.jsonObject(with:jsonData!,options:.mutableLeaves) as! Array<Any>
//print(arrayMain!)
if let firstDictionart=arrayMain![0] as? [String: Any] {
if let insideFirstDict = firstDictionart["validation"] as? [String: Any]{
print(insideFirstDict["bValid"]!)
print( insideFirstDict["sDescription"]!)
}
}
if let resultDictionary=arrayMain![1] as? [String: Any] {
if let serviceDictionary = resultDictionary["result"] as? [String: Any] {
for array in serviceDictionary["serviceCenter"] as! Array<Any>{
if let infoDicti=array as? [String: Any] {
print( infoDicti["color"]!)
print( infoDicti["make"]!)
print( infoDicti["color"]!)
print( infoDicti["sTag"]!)
print( infoDicti["sVin"]!)
print( infoDicti["sMiles"]!)
print( infoDicti["sVin"]!)
print( infoDicti["model"]!)
print( infoDicti["bDamage"]!)
print( infoDicti["dDateTime"]!)
}
}
}
}

core data with duplicate entity values in swift

I am parsing some data from Json and saved into the coredata,after fetching core data showing into the tableview working fine, tableview is show all the value in repeatedly how can avoid the repeated values I tried many ways but not find way
Json format
{
"contacts": [
{
"id": "c200",
"name": "Ravi Tamada",
"email": "ravi#gmail.com",
"address": "xx-xx-xxxx,x - street, x - country",
"gender" : "male",
"phone": {
"mobile": "+91 0000000000",
"home": "00 000000",
"office": "00 000000"
}
},
{
"id": "c201",
"name": "Johnny Depp",
"email": "johnny_depp#gmail.com",
"address": "xx-xx-xxxx,x - street, x - country",
"gender" : "male",
"phone": {
"mobile": "+91 0000000000",
"home": "00 000000",
"office": "00 000000"
}
},
{
"id": "c202",
"name": "Leonardo Dicaprio",
"email": "leonardo_dicaprio#gmail.com",
"address": "xx-xx-xxxx,x - street, x - country",
"gender" : "male",
"phone": {
"mobile": "+91 0000000000",
"home": "00 000000",
"office": "00 000000"
}
}
]
}
when I fetching "name" showing repeated values
these are save and fetch code
func getfetchdata()
{
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Contacts")
do{
let fetchResults = try self.context.fetch(fetchRequest) as? [Contacts]
if fetchResults!.count > 0 {
for bEntity in fetchResults! {
let employeeEntity = bEntity
print(employeeEntity.name as Any)
TableviewData.append(ContactsDataVal.init(name: employeeEntity.name!,
id: employeeEntity.id!, email: employeeEntity.email!, gender: employeeEntity.gender!, address: employeeEntity.address!))
}
print("data values already")
}}
catch let error as NSError
{
print(error)
}
}
func getdata()
{
let url = URL(string: "https://api.androidhive.info/contacts/")
URLSession.shared.dataTask(with: url!) { (Data, response, error) in
do
{
let data = try JSONSerialization.jsonObject(with: Data!, options: JSONSerialization.ReadingOptions.allowFragments)as! [String:AnyObject]
let arraydata = data["contacts"]as! [[String:Any]]
for arravalues in arraydata
{
let entityDescription = NSEntityDescription.entity(forEntityName: "Contacts", in:self.context)
let favouriteObj = Contacts(entity: entityDescription!, insertInto: self.context)
favouriteObj.name = arravalues["name"] as? String
favouriteObj.id = arravalues["id"] as? String
favouriteObj.email = arravalues["email"] as? String
favouriteObj.gender = arravalues["gender"] as? String
favouriteObj.address = arravalues["address"] as? String
do {
try self.context.save()
}
}
}catch let error as NSError{
print("error",error)
}
}
.resume()
}
how to avoid repeated values in core data and show proper data into the tableview
First of all in getdata do not save the context in each iteration of the loop, save it once after the loop.
To avoid duplicates fetch all contacts from Core Data, map them to the names and check if the array contains the received name
func getdata()
{
let url = URL(string: "https://api.androidhive.info/contacts/")
let names : [String]
do {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Contacts")
let fetchResults = try self.context.fetch(fetchRequest)
names = fetchResults.map{ $0.name }
} catch {
names = []
}
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil { print(error!); return }
do {
let data = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
let arraydata = data["contacts"] as! [[String:Any]]
for arravalues in arraydata
{
guard let name = arravalues["name"] as? String, !names.contains(name) else { continue }
let entityDescription = NSEntityDescription.entity(forEntityName: "Contacts", in:self.context)
let favouriteObj = Contacts(entity: entityDescription!, insertInto: self.context)
favouriteObj.name = name
favouriteObj.id = arravalues["id"] as? String
favouriteObj.email = arravalues["email"] as? String
favouriteObj.gender = arravalues["gender"] as? String
favouriteObj.address = arravalues["address"] as? String
}
try self.context.save()
} catch {
print("error",error)
}
}
.resume()
}
Notes:
A Core Data fetch with generic fetch request returns always a non-optional array of the NSManagedObject subclass which is specified as generic type on success.
Never check for empty array with foo.count > 0, use !foo.isEmpty
A JSON dictionary in Swift 3+ is always [String:Any] rather than [String:AnyObject]
Handle a potential error in the dataTask completion block.
Name the first parameter in the completion block lowercased (data) to avoid a confusion with the type Data.
Omit the options parameter in jsonObject(with as the result is clearly a collection type.
Maybe there is something that can be done to the fetch request similar to How to get distinct results from a single field in Core Data (Swift 4) but another option would be to remove the duplicates by simply creating a set from the fetch result:
let fetchSet = Set(fetchResults)
and iterate over the set instead

How to parse Array of JSON to array in Swift

I'm trying to parse JSON which is like below
[
{
"People": [
"Jack",
"Jones",
"Rock",
"Taylor",
"Rob"
]
},
{
"People": [
"Rose",
"John"
]
},
{
"People": [
"Ted"
]
}
]
to an array which results in:
[ ["Jack", "Jones", "Rock", "Taylor", "Rob"] , ["Rose", "John"], ["Ted"] ]
which is array of arrays.
I tried with code below
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? [AnyObject]
for people in peoplesArray! {
print(people)
}
}
when I print "people" I get o/p as
{
People = (
"Jack",
"Jones",
"Rock",
"Taylor",
"Rob"
);
}
{
People = (
"Rose",
"John"
);
}
...
I'm confused how to parse when it has "People" repeated 3 times
Trying to display content in UITableView where my 1st cell has "Jack" .."Rob" and Second cell has "Rose" , "John" and third cell as "Ted"
PLease help me to understand how to achieve this
You can do this in an elegant and type safe way leveraging Swift 4 Decodable
First define a type for your people array.
struct People {
let names: [String]
}
Then make it Decodable, so that it can be initialised with a JSON.
extension People: Decodable {
private enum Key: String, CodingKey {
case names = "People"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self)
self.names = try container.decode([String].self, forKey: .names)
}
}
Now you can easily decode your JSON input
guard
let url = Bundle.main.url(forResource: "People", withExtension: "json"),
let data = try? Data(contentsOf: url)
else { /* Insert error handling here */ }
do {
let people = try JSONDecoder().decode([People].self, from: data)
} catch {
// I find it handy to keep track of why the decoding has failed. E.g.:
print(error)
// Insert error handling here
}
Finally to get get your linear array of names you can do
let names = people.flatMap { $0.names }
// => ["Jack", "Jones", "Rock", "Taylor", "Rob", "Rose", "John", "Ted"]
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)
}
let assume that the json is the encoded data
var arrayOfData : [String] = []
dispatch_async(dispatch_get_main_queue(),{
for data in json as! [Dictionary<String,AnyObject>]
{
let data1 = data["People"]
arrayOfData.append(data1!)
}
})
You can now use the arrayOfData. :D
what you have here is first an array of 3 objects. each object is a dictionary where the key is people and the value is an array of strings. when you're trying to do jsonserialization, you have to cast it down to the expected result. So you have first an array of objects, then you have a dictionary with String: Any, then you obtain an array of String
let peoplesArray = try! JSONSerialization.jsonObject(with: Data(contentsOf: URL(fileURLWithPath: path)), options: []) as? [AnyObject]
guard let peoplesObject = peoplesArray["people"] as? [[String:Any]] else { return }
for people in peoplesObject {
print("\(people)")
}
I couldn't pasted it in a comment, it is too long or something
static func photosFromJSONObject(data: Data) -> photosResult {
do {
let jsonObject: Any =
try JSONSerialization.jsonObject(with: data, options: [])
print(jsonObject)
guard let
jsonDictionary = jsonObject as? [NSObject: Any] as NSDictionary?,
let trackObject = jsonDictionary["track"] as? [String: Any],
let album = trackObject["album"] as? [String: Any],
let photosArray = album["image"] as? [[String: Any]]
else {
return .failure(lastFMError.invalidJSONData)
}
}
}
And the json was something like:
{
artist: {
name: Cher,
track: {
title: WhateverTitle,
album: {
title: AlbumWhatever,
image: {
small: "image.px",
medium: "image.2px",
large: "image.3px"}
....

JSON Structure for parsing JSON data

I want to parse this JSON,at the top level incoming JSON is an array,how can access to information of dictionary in array?
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere#april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
]
that is my code but I don't know how detect dictionary data.
func profileFromJSONData(data : NSData) -> ProfileResult {
do{
let jsonObject : [[String:AnyObject]]
= try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [[String:AnyObject]]
for profileJSON in jsonObject {
if let profile = profileFromJsonObject(profileJSON) {
finalProfile.append(profile)
}
}
return .Success(finalProfile)
}
catch let error {
return .Failure(error)
}
}
it is my profileFromJsonObject method for parse JSON into profile instance
func profileFromJsonObject(json: [String:AnyObject]) -> UserProfile?{
guard let
id = json["id"] as? Int,
name = json["name"] as? String,
userName = json["username"] as? String,
email = json["email"] as? String,
address = json["address"] as? NSDictionary,
phone = json["phone"] as? String,
website = json["website"] as? String,
company = json["company"] as? NSDictionary
else {
return nil
}
let obj = UserProfile(id: id, name: name, userName: userName, email: email, address: address, phone: phone, website: website, company: company)
return obj
}
I tried your JSON by taking it in local file, and I am able to parse to the model object in following way.
You just put your remote JSON in my code, i hope it will work
func getTheLocalJSON()
{
let filePath = NSBundle.mainBundle().pathForResource("test", ofType: "json");
let data = NSData.init(contentsOfFile: filePath!);
var json : NSArray!
do{
json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSArray;
}catch{
}
print("json \(json)");
let dictResponse = json.objectAtIndex(0) as! NSDictionary;
let objUser = profileFromJsonObject(dictResponse)! as UserProfile;
print("user : \(objUser)");
//Code to access company name and show it as screen title
self.title = (objUser.company)!["name"] as? String;
lblCompanyname.text = (objUser.company)!["name"] as? String;
lblCatchPhrase.text = (objUser.company)!["catchPhrase"] as? String;
lblbs.text = (objUser.company)!["bs"] as? String;
}
func profileFromJsonObject(json: NSDictionary) -> UserProfile?{
guard let
id = json["id"] as? Int,
name = json["name"] as? String,
userName = json["username"] as? String,
email = json["email"] as? String,
address = json["address"] as? NSDictionary,
phone = json["phone"] as? String,
website = json["website"] as? String,
company = json["company"] as? NSDictionary
else {
return nil
}
let obj = UserProfile(id: id, name: name, userName: userName, email: email, address: address, phone: phone, website: website, company: company)
return obj
}
Output :

Resources