I'm trying to parse some JSON, this is what it's returning when I directly go to the URL:
[{"Password":"whatever1"}]
My code is able to receive the data correctly (when I debugged the variable "data" had the above JSON) however when trying to Parse it, it won't work. I think it might have to do with the square brackets, cause I've been parsing other JSONs without the square brackets and it works well.
Here is my code:
func SignIn (username: String, password: String, completion: #escaping (Bool)->())
{
let url = URL(string: "http://<myIP>/API/SignIn.php?username=\(username)");
let task = URLSession.shared.dataTask(with: url!)
{ (data, response, error) in
if let data = data
{
do
{
// Convert the data to JSON
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
// print( jsonSerialized)
if let json = jsonSerialized, let result = json["Password"]
{
print(result)
if (String(describing: result) == password)
{
completion(true)
}
else
{
completion(false)
}
// TODO: password is wrong,
// TODO: username is wrong
// TODO: else if timeout
}
}
catch let error as NSError {
print(error.localizedDescription)
completion(false)
}
}
else if let error = error
{
print(error.localizedDescription)
completion(false)
}
}
task.resume()
}
Rewrite code to :
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [[String : Any]]
This is needed as your JSON response is an array of dictionaries, like the others have mentioned.
Access the result using:
let result = json.first["Password"]
Related
I have this issue when trying to read my data which is json encoded from the php page to the swift page.
this is the code I am using
import Foundation
protocol HomeModelProtocol: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject, URLSessionDataDelegate {
//properties
weak var delegate: HomeModelProtocol!
var data = Data()
let urlPath: String = "http://localhost/service.php" //this will be changed to the path where service.php lives
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded") // this work fine
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
print(jsonResult) // this print empty parentheses
print(String(data: data, encoding: .utf8)) // this prints out the array
//the code below throughs an arror
do{
jsonResult = try JSONSerialization.jsonObject(with:data, options:JSONSerialization.ReadingOptions.allowFragments) as! [NSArray] as NSArray
print(jsonResult)
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let locations = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let location = LocationModel()
//the following insures none of the JsonElement values are nil through optional binding
if let name = jsonElement["Name"] as? String,
let address = jsonElement["Address"] as? String,
let latitude = jsonElement["Latitude"] as? String,
let longitude = jsonElement["Longitude"] as? String
{
location.name = name
location.address = address
location.latitude = latitude
location.longitude = longitude
}
locations.add(location)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: locations)
})
}
}
this is the output which I am receiving:
Data downloaded
(
)
Optional(" \nconnectedinside[{\"name\":\"One\",\"add\":\"One\",\"lat\":\"1\",\"long\":\"1\"},{\"name\":\"Two\",\"add\":\"Two\",\"lat\":\"2\",\"long\":\"2\"},{\"name\":\"One\",\"add\":\"One\",\"lat\":\"1\",\"long\":\"1\"},{\"name\":\"Two\",\"add\":\"Two\",\"lat\":\"2\",\"long\":\"2\"}]")
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around
character 2." UserInfo={NSDebugDescription=Invalid value around
character 2.}
You get this error, because the json response you receive is not an array but a dictionary.
EDIT: as pointed out in a comment, you first need to fix your json response in your php code. There is ":" missing after "connectedinside".
It should look like this:
{\"connectedinside\":[{\"name\":\"One\",\"add\":"One",...},...]}
My suggestion to fix this:
You should have two models:
struct HomeModelResponse: Codable {
let connectedinside: [LocationModel]
}
// your LocationModel should look like this:
struct LocationModel: Codable {
let name: String
let add: String
let lat: String
let long: String
}
And change your JSONDecoding code to:
do {
jsonResult = try? JSONDecoder().decode(HomeModelResponse.self, from: data)
print()
} catch let exception {
print("received exception while decoding: \(exception)"
}
Then you can access your LocationModels by jsonResult.connectedinside
The problem was on my php side and I fixed it.it is working now.
i have the php file that return json_encode value and when i go to the http address they give me the value but
i cant get the value form the server side to my apps i have try many time but its not get it
func loadData() {
let url = NSURL(string: "http://example.com/getExpo.php")
let request = NSMutableURLRequest(URL: url!)
// modify the request as necessary, if necessary
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
if error != nil {
// Display an alert message
print(error)
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
if (json != nil) {
//let userId = parseJSON["userId"] as? String
// Display an alert message
let userMessage = json!["id"] as? String
print(userMessage)
} else {
// Display an alert message
let userMessage = "Could not fetch Value"
print(userMessage)
}
} catch {
print(error)
}
}).resume()
}
any one can help , thank you !!
Your JSON response is an array of dictionaries:
[{"id":"115","expoName":"aziz","expoDetails":"aziz","expoPhone":"aziz","expoLocation":"aziz"}]
But you're trying to cast it as a Dictionary:
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
The solution of course is to cast it as an array:
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
Better use Swift types if you can:
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[String:AnyObject]]
Then for example you can use a loop:
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[String:AnyObject]] {
for item in json {
let userMessage = item["id"] as? String
}
}
I'm new to Swift and JSON and am having trouble. I have looked at all sorts of Q&A's here and tried incorporating the advice, but am failing to do so correctly.
I have the server generating JSON which is ok according to a JSON lint checker (http://jsonlint.com).
Using a browser, the response is this:
[{"PostalCode":"NW4 2JL"},{"PostalCode":"NW4 2ES"},{"PostalCode":"NW4 3XP"},{"PostalCode":"NW4 4DU"},{"PostalCode":"NW4 2HH"},{"PostalCode":"NW4 2DR"},{"PostalCode":"NW4 2DX"}]
Xcode, however, gives me this error:
Error, sorry, could not parse JSON: Optional([{"PostalCode":"NW4 2JL"},{"PostalCode":"NW4 2ES"},{"PostalCode":"NW4 3XP"},{"PostalCode":"NW4 4DU"},{"PostalCode":"NW4 2HH"},{"PostalCode":"NW4 2DR"},{"PostalCode":"NW4 2DX"}])
What baffles me, and I can find no explanation for, is the 'Optional()' part. Prior to that, the error statement is as I wrote it, on line 12 (the only message that includes the word 'sorry'). The JSON inside the '()' looks fine.
Can anyone advise what I've done wrong here, or at least where the 'Optional()' text is coming from?
This is the relevant portion of my code:
let task = session.dataTaskWithRequest(request) { data, response, error in
guard data != nil else {
print("no data found: \(error)")
return
}
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as? NSDictionary {
let success = json["success"] as? Int
print("Success: \(success)")
} else {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error, sorry, could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
With this line:
let success = json["success"] as? Int
you're making success an Optional. And since optionals conform to the protocol CustomStringConvertible, you get "Optional(...)" as a string.
If you don't know yet what is an Optional, stop everything and go learn about it. Now. ;)
Done? Ok, now safely unwrap the optional with, for example, optional binding:
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
if let success = json["success"] as? Int {
print("Success: \(success)")
}
}
That's it.
Note that here we're accessing a dictionary, but in your question the JSON is an array of dictionaries: it's a bit unclear what you actually have.
I perform a NSURLSession to get data from a php, which is a JSON. When I do NSJSONSerialization and store it as a NSArray everything works fine but when I try to access an element of it to put it in a table view it crashes with the error found nil while unwrapping an optional value. The JSON it returns looks like this:
[
{
"title":"data",
"value":"data"
}, ...
]
The code I'm using to get the value is:
self.arrayJSON[indexPath.row]["title"]
And when I try this in the Xcode console returns this:
▿ Optional(some data)
- Some : some data
EDIT:
JSON parsing code:
let task = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
do {
let responseJSON : NSArray = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as! NSArray
self.arrayJSON = NSMutableArray(array: responseJSON)
dispatch_async(dispatch_get_main_queue()) {
self.listaAnuncios.reloadData()
}
} catch {
print("json error")
}
}
task.resume()
I found the problem! It wasn't because of accessing to the element, it was because the cell was nil. I was using this:
let cell : CustomCell = CustomCell()
and I changed it for this:
let cell = tableView.dequeueReusableCellWithIdentifier("customCell", forIndexPath: indexPath) as! CustomCell
Here's the usual JSON I see:
{"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]}
But I am trying to parse this format of JSON, without the object ("employees" from the example above):
[{"id":"1","company":"1","facility":"2","starttime":"1454936400","complete_time":"1454979600","scheduled_hours":"12"},{"id":"3","company":"1","facility":"2","starttime":"1455021660","complete_time":"1455061660","scheduled_hours":"12"}]
Here's the code that I'm trying to use:
let requestURL: NSURL = NSURL(string: url)!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
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 stations = json[1] as? [[String: AnyObject]] {
print(json)
for station in stations {
if let name = station["company"] as? String {
print(name)
}
}
}
}catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
But I am not able to output any of the values from JSON data. How do I do it? I am very new in Swift and XCode.
Or if I can format my data to look like the first JSON, would it be alright? The data is being returned as an array from an SQL query.
UPDATE: When I print(json[1]) it only prints the second set. I think I'm getting closer.
NSJSONSerialization.JSONObjectWithData can be tricky because it can return either an Array aka [AnyObject] or a Dictionary aka [String: AnyObject].
Then you have to test what the result is :
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let json = jsonData as? [[String: AnyObject]] {
// json starts with an array
for value in json {
// loop through array
}
} else if let json = jsonData as? [String: AnyObject] {
// json starts with a key
for (key, value) in json {
// loop through dictionary key/values
}
} else {
// This json is broken
}
1-check that statusCode condition is true(200 or "200"?)
2-print data before try catch
if (statusCode == 200) {
print(data)
do{
......
}
3- print json object
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
print(json)
and
4-check json[1] same as [[String: AnyObject]]