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.
Related
Hi all I am trying my hands on Swift and I am trying to post users registration data. I know how to do it firebase but my main project is in php mysql so I want to connect it with swift
#IBAction func signUp(_ sender: Any) {
//check textfield data
checkTextFields()
//create user
let url = NSURL(string: "http://localhost:8888/helo/register.php")
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
//apending body to url
let body = "Fullname=\(name.text!.lowercased())&userName=\(userName.text!.lowercased())&emailAddress=\(emailAddress.text!.lowercased())&password=\(password.text!.lowercased())"
request.httpBody = body.data(using: String.Encoding.utf8)
//lunching
URLSession.shared.dataTaskWithRequest(request as URLRequest, completionHandler: { (data:NSData?, response:URLResponse?, error:NSError?) in
if error == nil{
dispatch_async(dispatch_get_main_queue(),{
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as?
NSDictionary
guard let parseJSON = json else{
print("Error while parsing")
return
}
let id = parseJSON["id"]
if id != nil {
print(parseJSON)
}
}catch{
print("Caugth an error: \(error)")
}
})
}else{
print("error: \(error)")
}
} )
}
I am getting an error on the line where I have commented as as lunching which say
Cannot convert value of type '(NSData?, URLResponse?, NSError?) -> ()' to expected argument type '(Data?, URLResponse?, Error?) -> Void'
I am new to Swift any help is welcome thank you all. I am using Xcode 9
After enough reading, I just realised I was doing a very tedious and using orthodox method when things have improved. I removed the whole code and did everything with Alamofire. Its really easy and straight forward. I will post the code below to help others who encounter similar problems later on.
//Constant that holds the URL for our web servicer
let URL_USER_REGISTER = "http://localhost:8888/members/register.php?"
Alamofire.request(URL_USER_REGISTER, method: .post, parameters: parameters).responseJSON{
response in
//printing response
print(response)
//getting json value from the server
if let result = response.result.value {
//converting it as NSDictionary
let jsonData = result as! NSDictionary
//displaying the message in label
self.lableMessage.text = jsonData.value(forKey: "message") as! String?
}
}
you have to first import Alamofire.
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"]
I'm currently on a project where I have to submit some data to PHP file and get the return from PHP.
Problem
When I try to do that using iOS URLSession, I'm getting an error,
The data couldn’t be read because it isn’t in the correct format.
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set."
UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
Because of this error, I made a sample php file where I return the value which I sent from Swift. And still getting this error along with some additional information.
<NSHTTPURLResponse: 0x60400042e200> { URL: http://192.168.1.99/insertDataTest.php } { status code: 200, headers {
Connection = "Keep-Alive";
"Content-Length" = 5;
"Content-Type" = "application/json";
Date = "Thu, 07 Dec 2017 09:55:58 GMT";
"Keep-Alive" = "timeout=5, max=100";
Server = "Apache/2.4.10 (Raspbian)";
} }
What I've done so far
Here I know the content coming from the PHP, cannot be read by Swift.
I'm sending a 5 digit string from Swift to PHP and since I'm returning it without doing anything, I'm getting length of 5 data. Also I manually added a code to php in orders to made header as application/json. But still getting this error. I'm sending json encoded data from PHP as well.
My Code
Swift:
let postParameters = "{\"usermobilenum\":12345}"
request.httpBody = postParameters.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest)
{
data, response, error in
if error != nil
{
print("error is \(String(describing: error))")
return;
}
do
{
print(response!)
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = myJSON
{
var msg : String!
msg = parseJSON["message"] as! String?
print(msg)
}
}
catch
{
print(error.localizedDescription)
print(error)
}
}
task.resume()
PHP :
<?php
header("Content-Type: application/json");
if($_SERVER["REQUEST_METHOD"]=="POST")
{
$data =json_decode(file_get_contents('php://input'),true);
$userPhone = $data["usermobilenum"];
echo json_encode($userPhone);
mysqli_close($connect);
}
else
{
echo json_encode("Failed in POST Method");
}
?>
I have no idea what this causes. I did try to find a solution for this in the internet and had no luck. Please help here. I'm using the latest Swift version.
Luckily I found the solution for my own problem. I missed to understand the error. As it says "option to allow fragments not set.", What I did was adding option .allowFragments. So the whole line after this replacement,
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary
And I could solve the problem and get the answer PHP returns.
So this is the piece of code causing a problem. It gives me a fatal error and says that an optional value is giving nil.
How do i fix this? This only works when I enter the first field only (the name field) and then submit, it pops up on my database. However, when I fill in more than one field, it crashes.
My code:
#IBAction func registerButtonTapped(sender: AnyObject) {
let strURL: String = "http://www.blabla.com.eg/blabla.php?name=\(nameField.text!)&company=\(companyField.text!)&email=\(emailField.text!)&phonenumber=\(phoneNumberField.text!)"
let dataURL: NSData = NSData(contentsOfURL: NSURL(string: strURL)!)!
let strResult: String = String(data: dataURL, encoding: NSUTF8StringEncoding)!
print("\(strResult)")
self.dismissViewControllerAnimated(true, completion: nil)
}
Your problem is that one (or more) of your optionals is nil when you try to access it. Its important to understand optionals if you are doing swift development, I'd recommend going through the documentation.
let dataURL: NSData = NSData(contentsOfURL: NSURL(string: strURL)!)!
let strResult: String = String(data: dataURL, encoding: NSUTF8StringEncoding)!
In the code above, when you use ! you are telling swift that you are 100% sure that optional contains a value. There might be an issue in either your construction of a url NSURL(strUrl)! or when calling the NSData(...) constructor and unwrapping its result with !.
Try something like this:
if let url = NSURL(string: strURL) {
if let data = NSData(contentsOfURL: url) {
var strResult = String(data: data, encoding: NSUTF8StringEncoding)
print(strResult ?? "Something Went Wrong")
}
else { // get rid of this else when you find your issue
print("Could not instantiate an NSData object out of that url")
}
}
else { // get rid of this else when you find your issue
print("Your URL is nil!, check the strUrl")
}
Here, we first unwrap the NSURL as NSURL(string) constructor returns an optional (the string you pass might be an invalid URL). We then unwrap the NSData object and then coalesce the strResult when printing it (as its also an optional).
I'm having trouble parsing a JSON, sent from a PHP script, on IOS using swift. I just started learning IOS development this week and also had never worked with JSON before so any help would be greatly appreciated on parsing this correctly. I'm sending a result from a mysql query as a JSON to the app. Here is my swift code and the error log in which you can see the object received by the http service.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let secondViewController:VC2 = segue.destinationViewController as! VC2
let myUrl = NSURL(string: "myscriptaddress");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
let postString = "condition=" + String(currentval);
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
secondViewController.mystring = "getting ready"
let task = NSURLSession.sharedSession().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: []) as? NSDictionary {
print("Success")
} else {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error can't parse JSON: '\(jsonStr)'")
}
}
task.resume()
}
And now the error log:
Error could not parse JSON: Optional([{"unidad":"sanfrancisco","capacidad":"15","uso":"5","telefono":"num"},{"unidad":"pediatricouniversitario","capacidad":"15","uso":"5","telefono":"num"},{"unidad":"sanjorge","capacidad":"15","uso":"7","telefono":"num"},{"unidad":"himacaguas","capacidad":"20","uso":"4","telefono":"num"},{"unidad":"himabayamon","capacidad":"20","uso":"8","telefono":"num"},{"unidad":"sanlucas","capacidad":"10","uso":"8","telefono":"num"},{"unidad":"auxiliomutuo","capacidad":"15","uso":"11","telefono":"num"}])
Its failing to unwrap the JSON data as a dictionary type. The JSON string provided is an array of objects.
Try this in your JSONObjectWithData call:
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[String : AnyObject]]