I am trying to load and parse countries names from json file using swift but I can't
This is file's format which I try to read: Countries JSON File
My code to do this task:
func getJsonFromUrl(){
let url = NSURL(string: COUNTRIES_URL)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
if let countries_array = jsonObj!.value(forKey: "name") as? NSArray {
for country in countries_array {
if let countryDict = country as? NSDictionary {
if let name = countryDict.value(forKey: "name") {
self.countries_names.append((name as? String)!)
}
}
}
}
OperationQueue.main.addOperation ({
self.showNames()
})
}
}).resume()
}
But when I run it, it gives me an error in this line: if let countries_array = jsonObj!.value(forKey: "name") as? NSArray {
because of an unexpected nil.
The JSON starts with a bracket ([) therefore the root object is an array
Don't use NSURL, NSArray and NSDictionary and value(forKey in Swift.
And handle possible errors.
func getJsonFromUrl() {
let url = URL(string: COUNTRIES_URL)!
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) -> Void in
if let error = error { print(error); return }
do {
if let countriesArray = try JSONSerialization.jsonObject(with: data!) as? [[String:String]] {
for country in countriesArray {
self.countries_names.append(country["name"]!)
}
}
} catch { print(error) }
OperationQueue.main.addOperation ({
self.showNames()
})
}).resume()
}
Or much more convenient with Decodable
struct Country : Decodable {
let name : String
}
func getJsonFromUrl() {
let url = URL(string: COUNTRIES_URL)!
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) -> Void in
if let error = error { print(error); return }
do {
let countries = try JSONDecoder().decode([Country].self, from: data!)
self.countries_names = countries.map{$0.name}
} catch { print(error) }
OperationQueue.main.addOperation ({
self.showNames()
})
}).resume()
}
It's an array not dictionary you need
if let dat = data {
if let jsonObj = try? JSONSerialization.jsonObject(with: dat, options:[]) as? [[String:String]]{
jsonObj.forEach { print($0["name"]) }
}
or use Codable
let res = try? JSONDecoder().decode([[String:String]].self,from:data)
or with model
struct Root: Codable {
let name : String
}
let res = try? JSONDecoder().decode([Root].self,from:data)
Code
func callAddWithPOST(Name mname:String, PhoneNo mphone:String, Email memail:String, Comment mcomments:String){
var names = [String]()
let login = ["countryId":"1"]
print("Your Result is : = \(login)")
let url = NSURL(string: "http://photokeeper.mgtcloud.co.uk/commonwebservice.asmx/getStateList")!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
do {
let auth = try NSJSONSerialization.dataWithJSONObject(login, options: .PrettyPrinted)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPMethod = "POST"
request.HTTPBody = auth
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
let badJsonString = "This really isn't valid JSON at all"
let badJsonData = badJsonString.dataUsingEncoding(NSUTF8StringEncoding)!
do {
let parsed = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments)
print(parsed)
let otherParsed = try NSJSONSerialization.JSONObjectWithData(badJsonData, options: NSJSONReadingOptions.AllowFragments)
}
catch let error as NSError {
print("A JSON parsing error occurred, here are the details:\n \(error)")
}
print("Done.")
})
task.resume()
} catch {
print("Error")
}}
OUTPUT
{
d = "{\"result\":[{\"stateId\":3871,\"stateName\":\"Aberdeenshire\"},{\"stateId\":3872,\"stateName\":\"Anglesey/Sir Fon\"},{\"stateId\":3873,\"stateName\":\"Angus\"},{\"stateId\":3874,\"stateName\":\"Antrim\"},{\"stateId\":3875,\"stateName\":\"Argyll And Bute\"},{\"stateId\":3876,\"stateName\":\"Armagh\"},{\"stateId\":3877,\"stateName\":\"Ayrshire\"},{\"stateId\":3878,\"stateName\":\"Bedfordshire\"},{\"stateId\":3879,\"stateName\":\"Berkshire\"},{\"stateId\":3880,\"stateName\":\"Blaenau Gwent/Blaenau Gwent\"},{\"stateId\":3881,\"stateName\":\"Bristol\"},{\"stateId\":3882,\"stateName\":\"Buckinghamshire\"},{\"stateId\":3883,\"stateName\":\"Caerphilly/Caerffili\"},{\"stateId\":3884,\"stateName\":\"Cambridgeshire\"},{\"stateId\":3885,\"stateName\":\"Cardiff/Caerdydd\"},{\"stateId\":3886,\"stateName\":\"Cardiganshire/Ceredigion\"},{\"stateId\":3888,\"stateName\":\"Carmarthenshire/Sir Gaerfyrddin\"},{\"stateId\":3890,\"stateName\":\"Cheshire\"},{\"stateId\":3891,\"stateName\":\"Clackmannanshire\"},{\"stateId\":3893,\"stateName\":\"Conwy/Conwy\"},{\"stateId\":3895,\"stateName\":\"County Durham\"},{\"stateId\":3896,\"stateName\":\"Cumbria\"},{\"stateId\":3897,\"stateName\":\"Denbighshire/Sir Ddinbych\"},{\"stateId\":3898,\"stateName\":\"Derbyshire\"},{\"stateId\":3899,\"stateName\":\"Devon\"},{\"stateId\":3901,\"stateName\":\"Dorset\"},{\"stateId\":3902,\"stateName\":\"Down\"},{\"stateId\":3904,\"stateName\":\"Dumfries And Galloway\"},{\"stateId\":3905,\"stateName\":\"Dunbartonshire\"},{\"stateId\":3906,\"stateName\":\"Dundee\"},{\"stateId\":3907,\"stateName\":\"Durham/North Yorkshire\"},{\"stateId\":3908,\"stateName\":\"East Lothian\"},{\"stateId\":3909,\"stateName\":\"East Sussex\"},{\"stateId\":3910,\"stateName\":\"East Yorkshire\"},{\"stateId\":3911,\"stateName\":\"Edinburgh\"},{\"stateId\":3912,\"stateName\":\"Essex\"},{\"stateId\":3913,\"stateName\":\"Fermanagh\"},{\"stateId\":3914,\"stateName\":\"Fife\"},{\"stateId\":3915,\"stateName\":\"Flintshire/Sir Fflint\"},{\"stateId\":3917,\"stateName\":\"Glamorgan/Morgannwg\"},{\"stateId\":3918,\"stateName\":\"Glasgow\"},{\"stateId\":3919,\"stateName\":\"Gloucestershire\"},{\"stateId\":3920,\"stateName\":\"Gwynedd/Gwynedd\"},{\"stateId\":3921,\"stateName\":\"Hampshire\"},{\"stateId\":3922,\"stateName\":\"Herefordshire\"},{\"stateId\":3923,\"stateName\":\"Hertfordshire\"},{\"stateId\":3924,\"stateName\":\"Highland\"},{\"stateId\":3925,\"stateName\":\"Kent\"},{\"stateId\":3929,\"stateName\":\"Lanarkshire\"},{\"stateId\":3930,\"stateName\":\"Lancashire\"},{\"stateId\":3932,\"stateName\":\"Leicestershire\"},{\"stateId\":3935,\"stateName\":\"Lincolnshire\"},{\"stateId\":3936,\"stateName\":\"London\"},{\"stateId\":3937,\"stateName\":\"Londonderry\"},{\"stateId\":3940,\"stateName\":\"Manchester\"},{\"stateId\":3943,\"stateName\":\"Merthyr Tydfil/Merthyr Tydfil\"},{\"stateId\":3944,\"stateName\":\"Midlothian\"},{\"stateId\":3946,\"stateName\":\"Monmouthshire/Sir Fynwy\"},{\"stateId\":3947,\"stateName\":\"Moray\"},{\"stateId\":3948,\"stateName\":\"Neath Port Talbot\"},{\"stateId\":3949,\"stateName\":\"Newport\"},{\"stateId\":3950,\"stateName\":\"Norfolk\"},{\"stateId\":3951,\"stateName\":\"Northamptonshire\"},{\"stateId\":3952,\"stateName\":\"Northumberland\"},{\"stateId\":3953,\"stateName\":\"Nottinghamshire\"},{\"stateId\":3955,\"stateName\":\"Orkney\"},{\"stateId\":3956,\"stateName\":\"Oxfordshire\"},{\"stateId\":3957,\"stateName\":\"Pembrokeshire/Sir Benfro\"},{\"stateId\":3958,\"stateName\":\"Perth And Kinross\"},{\"stateId\":3959,\"stateName\":\"Powys/Powys\"},{\"stateId\":3960,\"stateName\":\"Renfrewshire\"},{\"stateId\":3962,\"stateName\":\"Rutland\"},{\"stateId\":3963,\"stateName\":\"Scottish Borders\"},{\"stateId\":3964,\"stateName\":\"Shetland Isles\"},{\"stateId\":3965,\"stateName\":\"Shropshire\"},{\"stateId\":3967,\"stateName\":\"Somerset\"},{\"stateId\":3968,\"stateName\":\"South Yorkshire\"},{\"stateId\":3969,\"stateName\":\"Staffordshire\"},{\"stateId\":3970,\"stateName\":\"Stirling\"},{\"stateId\":3971,\"stateName\":\"Suffolk\"},{\"stateId\":3972,\"stateName\":\"Surrey\"},{\"stateId\":3973,\"stateName\":\"Swansea\"},{\"stateId\":3975,\"stateName\":\"Torfaen\"},{\"stateId\":3976,\"stateName\":\"Tyrone\"},{\"stateId\":3977,\"stateName\":\"Warwickshire\"},{\"stateId\":3979,\"stateName\":\"West Lothian\"},{\"stateId\":3980,\"stateName\":\"West Midlands\"},{\"stateId\":3981,\"stateName\":\"West Sussex\"},{\"stateId\":3982,\"stateName\":\"West Yorkshire\"},{\"stateId\":3983,\"stateName\":\"Western Isles\"},{\"stateId\":3987,\"stateName\":\"Wiltshire\"},{\"stateId\":3988,\"stateName\":\"Worcestershire\"},{\"stateId\":3989,\"stateName\":\"Wrexham\"}],\"status\":\"success\"}";
}
A JSON parsing error occurred, here are the details:
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
Done.
I AM GETTING ERROR - Invalid value around character 0. I want to get data in proper format with desired key and value, will anybody please help me to fix this issues.
Your JSON response is corrupted. Use JSONLint to verify it.
Convert it from
{\"result\":[{\"stateId\":3871,\"stateName\":\"Aberdeenshire\"}
to
{
"result": {
"stateId": 3871,
"stateName": "Aberdeenshire"
}
}
Notice the removal of the backslashes.
Looks like you are getting String in your response, so try something like this.
do {
let parsed = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! [String: AnyObject]
let responseStr = parsed["d"] as! String
let correctData = responseStr.dataUsingEncoding(NSUTF8StringEncoding)
let responseDic = try NSJSONSerialization.JSONObjectWithData(correctData, options: NSJSONReadingOptions.AllowFragments) as! [String: AnyObject]
print(responseDic)
}
catch let error as NSError {
print("A JSON parsing error occurred, here are the details:\n \(error)")
}
Try this,
if let result:String = parsed["d"]! {
let result = convertStringToDictionary(text: result)
print("Converted result = \(result)")
}
//SWIFT 3
func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.data(using: String.Encoding.utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject]
} catch let error as NSError {
print(error)
}
}
return nil
}
//SWIFT 2
func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.dataUsingEncoding(NSUTF8StringEncoding) {
do {
return try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String:AnyObject]
} catch let error as NSError {
print(error)
}
}
return nil
}
When I try to run this project I am greeted with a "Use of unresolved identifier error." Here is the code I get the error on the line with
var jsonDict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
as! NSDictionary
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if((error) != nil) {
print(error!.localizedDescription)
} else {
let err: NSError?
do {
var jsonDict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
} catch {
if(err != nil) {
print("JSON Error \(err!.localizedDescription)")
}
else {
//5: Extract the Quotes and Values and send them inside a NSNotification
let quotes:NSArray = ((jsonDict.objectForKey("query") as! NSDictionary).objectForKey("results") as! NSDictionary).objectForKey("quote") as! NSArray
dispatch_async(dispatch_get_main_queue(), {
NSNotificationCenter.defaultCenter().postNotificationName(kNotificationStocksUpdated, object: nil, userInfo: [kNotificationStocksUpdated:quotes])
})
}
}
}
})
can someone please help. Thank you.
You problem could be this line of code in the catch block.
let quotes:NSArray = ((jsonDict.objectForKey("query") as! NSDictionary).objectForKey("results") as! NSDictionary).objectForKey("quote") as! NSArray
In the above statement jsonDict is out of scope. You declared jsonDict in the do block but are trying to use it in the catch block.
Try Following:-
(Assuming JSON has a root node structure)
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: yourURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let queries = json["query"] as? [[String: AnyObject]] {
for query in queries {
if let quote = query["quote"] as? String {
self.quoteArr.append(quote)
}
}//for loop
dispatch_async(dispatch_get_main_queue(),{
// your main queue code
NSNotificationCenter.defaultCenter().postNotificationName(kNotificationStocksUpdated, object: nil, userInfo: [kNotificationStocksUpdated:quotes])
})//dispatch
}// if loop
}
catch
{
print("Error with Json: \(error)")
}
}
else
{
// No internet connection
// Alert view controller
// Alert action style default
}
this cobweb of code is exactly why SwiftyJSON library exists. I recommend it highly, it can be imported into your project using cocoapods.
using this library the resultant code would be
jsonQuery["query"]["results"]["quote"]
which is more readable and as you implement more APIs, much faster.
i try to using external database and api's. so i follow from this video in youtube
https://www.youtube.com/watch?v=Ixk93yx-v28
and i see this error
"Value of optional type 'NSURL?' not unwrapped; " on that line
func request(url:String,callback:(NSDictionary)->()) {
var nsURL = NSURL(string: url)
///////////////////////////on this line/////////////////////////////////
let task = NSURLSession.sharedSession().dataTaskWithURL(nsURL) {
/////////////////////////////////////////////////////////////////
(data,response,error) in
var error:NSError?
var response = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as NSDictionary
callback(response)
}
task.resume()
}
and when i try to fix by put ! in nsURL like this
xCode return this error "Extra argument 'error' in call "
func request(url:String,callback:(NSDictionary)->()) {
var nsURL = NSURL(string: url)
let task = NSURLSession.sharedSession().dataTaskWithURL(nsURL!) {
(data,response,error) in
var error:NSError?
////////////////////////////Error Here/////////////////////////////////////
var response = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: error) as NSDictionary
/////////////////////////////////////////////////////////////////////////////////
callback(response)
}
task.resume()
}
have any ideal ? sorry for my english
Update your function as shown below for swift 2.0:
func request(url:String,callback:(NSDictionary)->()) {
guard let nsURL = NSURL(string: url) else { return }
///////////////////////////on this line/////////////////////////////////
let task = NSURLSession.sharedSession().dataTaskWithURL(nsURL) {
/////////////////////////////////////////////////////////////////
(data, response, error) in
guard let data = data where error == nil else { return }
do {
if let response = try NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers) as? NSDictionary {
callback(response)
}
} catch let error as NSError {
print("json error: \(error.localizedDescription)")
}
}
task.resume()
}