I have a very similar problem like in Why the http post request body always wrapped by Optional text in the Swift app
but I can´t apply the solution from this thread to my code, because I don´t have a request.setValue.
Does anyone know what I need to do to get rid of the Optional?
My Code:
#IBAction func LoginButtonTapped(sender: UIButton) {
let username = UsernameTextField.text
let password = PasswordTextField.text
if(username!.isEmpty || password!.isEmpty) {return; }
let request = NSMutableURLRequest (URL: NSURL(string: "http://myip/loginregister.php")!)
request.HTTPMethod = "POST"
let postString = "username=\(username)&password=\(password)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard error == nil && data != nil else {
// check for fundamental networking error
print("error=\(error)")
return
}
let data = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
let success = json["success"] as? Int // Okay, the `json` is here, let's get the value for 'success' out of it
print("Success: \(success)")
} else {
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding) // No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
You must unwrapping the value when get text from UITextField first, because the text property of UITextField allow nil
let username = UsernameTextField.text!
let password = PasswordTextField.text!
Explain more
When you unwrap the text of the UITextField, the username and password will be not nil variable.
The code compare empty should be:
if(username.isEmpty || password.isEmpty) {return }
If you does not unwrap, when you use this "\(username)", your are try to convert a nilable object to string, so the string result will be appended with a "Optional" text.
To Solve problem with Content-Type for request
Paste this line to your code. I don't believe that you do not have setValue method.
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"Content-Type")
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 am trying to create an iOS app using Swift and I need to implement a search feature using UISearchbar. It takes in a store name and searches for it in the database to return an array of store names. Below is the segment of the code which is giving me some errors. I followed this website closely http://swiftdeveloperblog.com/case-insensitive-search-with-swift-php-and-mysql/
func searchBarSearchButtonClicked(_ searchBar: UISearchBar)
{
if(searchBar.text!.isEmpty)
{
return
}
doSearch(searchWord: searchBar.text!)
}
func doSearch(searchWord: String){
mysearchBar.resignFirstResponder()
let myURL = NSURL(string: "http://localhost:8080/searchStore.php")
var request = URLRequest(url:myURL! as URL)
request.httpMethod = "POST"
let postString = "name=\(searchWord)"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request, completionHandler:{ (data: Data?, response: URLResponse!, error: Error!) -> Void in
DispatchQueue.main.async() {
if error != nil{
self.displayAlertMessage(userMessage: error.localizedDescription)
return
}
do{
var _: Error?
//STOPPED HERE AS OF NOW
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
self.results.removeAll(keepingCapacity: false)
self.tableView.reloadData()
if let parseJSON = json{
if let stores = parseJSON["stores"] as? [AnyObject]{
for storeOjb in stores{
let name = (storeOjb["name"] as! String)
self.results.append(name)
}
self.tableView.reloadData()
}else if(parseJSON["message"] != nil){
let errorMessage = parseJSON["message"] as? String
if(errorMessage != nil){
self.displayAlertMessage(userMessage: errorMessage!)
}
}
}
} catch {
print(error)
}
}
})
task.resume()
}
I get 2 errors the first one is due to mysearchBar.resignFirstResponder(). The app terminates and I keep getting
"fatal error: unexpectedly found nil while unwrapping an Optional value"
The second error is when I remove mysearchBar.resignFirstResponder() I get
Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo=
{NSDebugDescription=No value.}
UPDATE:
I fixed the 2nd problem by entering this line
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
However, it seems that my postString variable is facing a problem
breakpoint check photo
You should set a breakpoint on the line that is giving you the error by clicking on the line number and run the program. Look for nil values by using the bottom left debugger pane window.
This will help you find what value is nil and if you already know what variable is nil please tell us!
I have a function in Swift 3 to POST data to a PHP server. The PHP server send a JSon answer to iOS and I have an error.
This is my function :
func sendRequestPost(urlString: String, dataToPost: String, completion: #escaping (_ dictionary: NSDictionary?, _ error: Error?) -> Void) {
DispatchQueue.global(qos: .background).async {
var request = URLRequest(url: URL(string: urlString)!)
let postString = dataToPost
request.httpMethod = "POST"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // Check for fundamental networking error
print("error=\(error)")
completion(nil, error)
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // Check for http(s) errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
// make error here and then
completion(nil, error)
return
}
let responseString = String(data: data, encoding: .utf8)
print("responseString : \(responseString)!")
DispatchQueue.main.async {
print("DispatchQueue.main.async")
do {
print("enter do")
let jsonDictionary:NSDictionary = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any] as NSDictionary
print("jsonDictionary")
print(jsonDictionary)
completion(jsonDictionary, nil)
} catch {
print("CATCH ERROR !")
completion(nil, error)
}
}
}
task.resume()
}
}
For example I call my function like that :
let url = "https://mywebsite.com/signup/ios/signup.php"
let postData = "username=\(txtUsername.text!)&password=\(txtPassword.text!)&confirmPassword=\(txtConfirmPassword.text!)&email=\(txtEmail.text!)&firstname=\(txtFirstname.text!)&lastname=\(txtLastname.text!)"
sendRequestPost(urlString: url, dataToPost: postData) {
dictionary, error in
print("---directory---")
print(dictionary)
print("---error---")
print(error)
print("==========")
This is what I see in the console :
responseString : "{\"exception\":false,\"success\":false,\"status\":-9,\"message\":\"This username already exist !\",\"confirmMessage\":\"null\",\"html\":\"null\",\"data\":\"boblongueuil\"}"!
DispatchQueue.main.async
---ENTER DO :
CATCH ERROR !
---directory---
nil
---error---
Optional(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.})
So how can I return the JSon string after call this function to see a registration is OK or registration have a problem (in this case the username already exist in database). I change answer from my PHP server to an array.
This is my code and I am unable to compile it .
I am trying to login to my server but it doesnt allow me so
Sorry I am new at programming and I've researched on stackoverflow, regarding this error , I can only parse Dictionary or Array. but I've googled by copying my JSON response but it doesnt work.
Any Suggestions would be helpful !!
import UIKit
class Login: UIViewController {
#IBOutlet var Username: UITextField!
#IBOutlet var Password: UITextField!
#IBAction func Login(sender: UIButton) {
let username=Username.text
let password=Password.text
let URL_LOGIN="http://172.22.95.116/SoilCondition/app/getLogin.php?USERNAME=" + username! + "&PASSWORD=" + password!;
let requestURL = NSURL(string: URL_LOGIN)
let request = NSMutableURLRequest(URL: requestURL!)
request.HTTPMethod = "POST"
let postParameters = "username="+username!+"&password="+password!;
request.HTTPBody = postParameters.dataUsingEncoding(NSUTF8StringEncoding)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request){
data, response, error in guard let data = data where error == nil
else {
print("error: \(error)")
return
}
do{
let myJSON = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
if let parseJSON = myJSON{
var msg: String!
msg = parseJSON["message"] as! String?
print(msg)
}
/* if let parseJSON = myJSON {
var msg : String!
msg = parseJSON["message"] as! String?
print(msg)
}*/
/*if data != nil {
json = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
println("json: \(json)")
if let dictionary = parseJSON(jsonString) {
println("dictionary: \(dictionary)")
}*/
} catch let parseError{
print(parseError)
}
}
task.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I found this question regarding error code 3840.
As it says there, the problem could be that your server doesn't return valid JSON to you.
Now, you say:
I can only parse Dictionary or Array
I don't know if that means that you are able to actually parse the response you receive from the server into valid JSON here:
let myJSON = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
But if it doesn't then a good place to start could be to verify whether your server actually returns valid JSON to you.
To do so, you could try calling your server directly from cURL or postman and see what you get in return.
Hope that helps you.
The purpose of this code is to send data to a SQL database using PHP script.
But when I try to run it I get the following error:
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.}
This is my code:
// Send userdata to server side
let myURL = NSURL(string: "http://localhost/userRegister.php");
let request = NSMutableURLRequest(URL:myURL!);
request.HTTPMethod = "POST";
let postString = "email=\(userEmail)&password=\(userPassword)";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
// Create the task and execute it
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
data,response, error in
if error != nil{
print("error=\(error)")
return
}
var err: NSError?
do
{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let parseJSON = json {
var resultValue = parseJSON["status"] as? String
print("result: \(resultValue)")
var isUserRegisterd:Bool = false;
if(resultValue=="Success")
{
isUserRegisterd = true
}
var messageToDisplay: String = (parseJSON["message"] as? String)!
if(!isUserRegisterd)
{
messageToDisplay = (parseJSON["message"] as? String)!
}
dispatch_async(dispatch_get_main_queue(), {
var myAlert = UIAlertController(title: "Alert", message: messageToDisplay, preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title: "Oké", style: UIAlertActionStyle.Default){
action in
self.dismissViewControllerAnimated(true, completion: nil);
}
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated: true, completion: nil);
});
}
}
catch
{
print(error)
}
}
task.resume()
What is the problem here?
That error generally means that the NSData doesn't contain valid JSON.
You should look at the response and the string representation of the data because if the server encountered a problem, it most likely would have returned a statusCode in the NSHTTPURLResponse (where 200 means that everything was OK, RFC 2616 describes what the other error codes mean) and the NSData likely contains HTML or text describing the nature of the problem:
do {
// your code where you `try` parsing the JSON response goes here
} catch {
print(error)
if data != nil {
let string = String(data: data!, encoding: NSUTF8StringEncoding)
print(string)
}
print(response)
}
When you look at the NSURLResponse and NSData objects, you will you be far more likely to diagnose the problem.
--
By the way, I might advise specifying the Content-Type of the request. Also, I'd suggest percent-escaping the email address and password. The latter is important because if the values contain special characters (e.g. + and & are notable problems), the data will not be processed correctly by the server.
let url = NSURL(string: "http://localhost/userRegister.php")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let encodedEmail = userEmail.stringByAddingPercentEncodingForFormUrlencoded()
let encodedPassword = userPassword.stringByAddingPercentEncodingForFormUrlencoded()
let postString = "email=\(encodedEmail)&password=\(encodedPassword)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
Where
extension String {
/// Percent escape value to be added to a HTTP request
///
/// This percent-escapes all characters besize the alphanumeric character set and "-", ".", "_", and "*".
/// This will also replace spaces with the "+" character as outlined in the application/x-www-form-urlencoded spec:
///
/// http://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
///
/// - returns: Return percent escaped string.
func stringByAddingPercentEncodingForFormUrlencoded() -> String? {
let allowedCharacters = NSCharacterSet(charactersInString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._* ")
return stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacters)?.stringByReplacingOccurrencesOfString(" ", withString: "+")
}
}
Alternatively, you can build the character set of allowed characters by starting with URLQueryAllowedCharacterSet, but you still have to remove a few characters as it will otherwise that allows certain characters pass unescaped (e.g. +). See https://stackoverflow.com/a/35912606/1271826.
Or you could use a framework like Alamofire which takes care of these details for you.
In my case, even the following code was causing this error by appending extra // slashes at the beginning of the output.
$arr = array("status" => 1, "msg" => "Your message goes here!");
echo json_encode($arr);
The reason was that these extra characters were being printed in other file that I included to this file.