I'm new to Swift 4 programming. It's my first iOS project. I'm having difficulties sending data to a server in JSON!
The server is recieving all the prameters textfields empty.
let pram = ["departement": departmentTextField.text, "fname": firstNameTextField.text, "lname": lastNameTextField.text, "email": emailTextField.text, "mbl": mobileNumberTextField.text, "address": residentialTextField.text,"subrub": suburbTextField.text,"dob": chooseDateofBTextField.text,"gender": genderTextField.text, "cardno": medicareCardNoTextField.text, "edate": medicareExpiryTextField.text, "source": howDidText.text, "condition": conditionTextField.text, "appdate": aptDOPTextField.text]
let url = URL(string: "//myAPI")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = pram
request.httpBody = (postString as AnyObject).data
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)")
let alert = UIAlertController(title: "Connection Lost ", message: "Please Try Again Later", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Done", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
let alert = UIAlertController(title: "Your Appointement has been placed", message: "", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Done", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
task.resume()
i would recommend you to use Almofire. It's a pretty simple bib. you can easily use it to send server requests just like that:
let parameters: Parameters = ["departement": departmentTextField.text!] //and so on
Alamofire.request("apiPath", method: .post, parameters: parameters).responseJSON { response in
if let json = response.result.value {
print("JSON: \(json)") // serialized json response
}
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)") // original server data as UTF8 string
}
}
according to your question you have to insert a "!" after the textfield's text.
Here is the almofire documentation: https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#making-a-request
Related
I have craeted a class called db_conn and inside this calass I have the following functions :
public func login (email : String , password : String ) -> String {
var result = ""
let url = URL(string: API.url_login.rawValue)!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = "email=\(email)&password=\(password)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("\(String(describing: response))")
}
let responseString = String(data: data, encoding: .utf8)
result = String(responseString!)
//print("responseString = \(responseString!)")
}
task.resume()
return result
}
and then in my login viewController class I try to use it like ==>
#IBAction func login_button_action(_ sender: UIButton) {
let email = email_text.text
let passw0rd = password_text.text
if (email != "" && passw0rd != ""){
let db_connect = db_conn()
if (db_connect.login(email: email!, password: passw0rd!) == nil ){
print("it's empty ")
}else {
print("not empty \(db_connect.login(email: email!, password: passw0rd!))")
}
}else {
let alert = UIAlertController(title: "Error", message: "Dont leave any of the spaces blank , they all must be filled up , try again ! ", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
when I run the project it says that the value for db_connect.login(email: email!, password: passw0rd!) is not empty but it doesnt print it out .
(However in my db_conn calss I can easily print the responseString and I get the returned JSON in String format .
Any idea where am I making my mistake ? And how can I possibly fix it ?
Making a network request with URLSession runs asynchronously, which means that iOS put it onto a background thread and continues the current thread immediately before the download is finished. Therefore, when you return result, it's still an empty string. What you probably want to do is pass a completion closure to your login method, and call that with the relevant data when it's finished downloading
Swift 3.0 (Xcode 8.3)
I'm trying to make a small program, that send a username to a web data base. I have found out how to send first_name, last_name,dob,owner_mobile,owner_email,
owner_password,choice_for_verification, by using in POST method. I obtain a JSON string earlier, then when I try to parse it, I get the above error on the try NSJSONSerialization line, on the as keyword. What did I do wrong? Thanks for your answers.
#IBAction func Login_Action(_ sender: Any)
{
var responseString : String!
var request = URLRequest(url: URL(string: "http://dev.justpick2go.com/cpanel/api/owner/ownerregistration.php")!)
request.setValue("Application/x-www.ownerregistration.php.com", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = "first_name=\(txtFirstName.text!)&last_name=\(txtLastName.text!)&dob=\(txtDOB.text!)&owner_mobile=\(txtMobileNo.text!)&owner_email=\(txtEmailID.text!)&owner_password=\(txtPassword.text!)" //&choice_for_verification=\(email)" // sending a parameters
print("\(postString)")
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error != nil else { //checking for fundamental error
print("Error is =\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200
{ // checking for http errors
print("statusCode should be 200 , but is\(httpStatus.statusCode)")
print("response is =\(String(describing: response))")
}
responseString = String(data: data, encoding: .utf8)
print("ResponseString=\(responseString!)")
do {
let json : NSDictionary! = try! JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSDictionary
self.parseTheJSonData(JsonData: json)
}
catch
{
print(error)
}
}
task.resume()
}
func parseTheJSonData(JsonData : NSDictionary)
{
var successMessage : String = String()
var sampleCode : Int = Int()
let verificationAlert = UIAlertController()
if ((JsonData.value(forKey: "success") as! Int) == 1)
{
successMessage = "Login is Successful"
sampleCode = JsonData.value(forKey: "success") as! Int
verificationAlert.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil))
verificationAlert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { (Relogin) in
let Log = self.storyboard?.instantiateViewController(withIdentifier: "") as! LoginViewController
self.navigationController?.pushViewController(Log, animated: true)
self.present(Log, animated: true, completion: nil)
}))
}
else if ((JsonData.value(forKey: "success") as! Int) == 0)
{
sampleCode = JsonData.value(forKey: "success") as! Int
successMessage = "Please try again"
verificationAlert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
}
verificationAlert.title = successMessage
OperationQueue.main.addOperation
{
self.present(verificationAlert, animated: true, completion: nil)
}
}
I have this chunk of code which posts json object to server
func postToServer(_ jsonObject: NSObject) -> Void {
var request = URLRequest(url: URL(string:url)!)
let session = URLSession.shared
request.httpMethod = "POST"
//Note : Add the corresponding "Content-Type" and "Accept" header. In this example I had used the application/json.
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try! JSONSerialization.data(withJSONObject: jsonObject, options: [])
let task = session.dataTask(with: request, completionHandler: { data, response, error in
guard data != nil else {
print("no data found: \(error)")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
print("Response: \(json)")
} else {
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)// 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: String.Encoding.utf8.rawValue)
print("Error could not parse JSON 2: '\(jsonStr)'")
self.alert(message: "test",title: "test")
}
})
task.resume()
}
My problem is this: I want to display alert to the user after I get response from server. For that I'm using this simple function:
func alert(message: String, title: String = "") {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion: nil)}
But, my app blocks after this. Any ideas?
Once the user click the login button, i will call the func LoginClicked and get the status from api:
func LoginClicked(sender: AnyObject)
{
data_request{
(response) -> () in
let arrResponse = response.componentsSeparatedByString("|")
if (arrResponse[2] == "1"){
self.performSegueWithIdentifier("Login", sender: self)
}
else {
let alert = UIAlertController(title: "Login Failed", message: "Invalid Login!", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
}
func data_request(completion : (response:NSString) -> ()){
let txtUI : String = txtUsername!.text!
let txtPWD : String = txtPassword!.text!
let url = NSURL(string: "http://myweb.net/?UI=\(txtUI)&PW=\(txtPWD)")!
let request = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(request, completionHandler: {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
completion(response : dataString!)
})
task.resume()
}
If success, it will move to another view. Otherwise, show failed alert. it will hit the error BAD_EXECUTION_INSTRUCTION when calling self. in both condition.
After get the hint from #Tj3n, it can do the proper action now.
func data_request(completion : (response:NSString) -> ()){
let txtUI : String = txtUsername!.text!
let txtPWD : String = txtPassword!.text!
let url = NSURL(string: "http://myweb.net/?UI=\(txtUI)&PW=\(txtPWD)")!
let request = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(request, completionHandler: {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
dispatch_async(dispatch_get_main_queue(), {
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
//let response = dataString?.componentsSeparatedByString("|")
//print(dataString)
//print(response![2])
let arrResponse = dataString!.componentsSeparatedByString("|")
if (arrResponse[2] == "1"){
self.performSegueWithIdentifier("Login", sender: self)
}
else {
let alert = UIAlertController(title: "Login Failed", message: "Invalid Login!", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
})
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
completion(response : dataString!)
})
task.resume()
}
In swift 2 When I'm communicating with a web-service and when I write these codes in button action it works fine.
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: .Alert)
let ok = UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in })
alert.addAction(ok);
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.myaddress.com/web-service/iostest.aspx")!)
request.HTTPMethod = "POST"
var postString = String();
postString = "uid=1";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard error == nil && data != nil else {
alert.title="Error"
alert.message = "Connection error"
dispatch_async(dispatch_get_main_queue()){
self.presentViewController(alert, animated: true, completion: nil)
}
return
}
if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 {
alert.title="Error"
alert.message = "Server error"
dispatch_async(dispatch_get_main_queue()){
self.presentViewController(alert, animated: true, completion: nil)
}
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
alert.title="Info"
alert.message = responseString as? String
dispatch_async(dispatch_get_main_queue()){
self.presentViewController(alert, animated: true, completion: nil)
}
}
task.resume()
As I said this works fine but as I want to do this from different ViewControls as well I have created a swift file which contains a struct and a static func in that struct that returns the the "responseString" so I could alert it in the view control. Something like this:
struct globalClass {
static func sendInfo(url: String, data: String) -> (answer: String, errorCode: Int32) {
var res = String();
var err = Int32();
err = 0;
let request = NSMutableURLRequest(URL: NSURL(string: url)!);
request.HTTPMethod = "POST";
let postString: String = data;
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard error == nil && data != nil else {
err = 1;
return;
}
if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 {
err = 2;
return;
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding);
res = (responseString as? String)!;
}
task.resume();
return (res, err);
}
But now when I call this func from my button it shows me an empty alert very fast that it seems like it didn't get anything from web-service and didn't even try too.
I put these in the button action:
#IBAction func btnData(sender: AnyObject) {
let y: String = "uid=1";
let res = globalClass.sendInfo("http://www.myaddress.com/web-service/iostest.aspx", data: y);
let alert = UIAlertController(title: "", message: "", preferredStyle: .Alert);
let OK = UIAlertAction(title: "OK", style: .Default, handler: nil);
alert.addAction(OK);
if (res.errorCode==0) {
alert.title = "Info";
alert.message = res.answer;
} else if (res.errorCode==1) {
alert.title = "Error";
alert.message = "Error connecting to server";
} else {
alert.title = "Error";
alert.message = "Server returned an error";
}
dispatch_async(dispatch_get_main_queue()){
self.presentViewController(alert, animated: true, completion: nil);
};
}
Thanks for the help,
Afshin Mobayen Khiabani
globalClass.sendInfo uses async call - dataTaskWithRequest. The result of the request will be delivered in completion of this method. But you don't wait for that result, instead you try to use sendInfo like a sync function.
To be able to deliver the result from dataTaskWithRequest's completion, put your own completion into sendInfo and invoke this completion (closure) when the result is delivered. An example
struct GlobalClass {
static func sendInfo(url: String, data: String, completion: (answer: String?, errorCode: Int32?) -> Void) {
// you code here which prepares request
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
// you parse the result here
// you deliver the result using closure
completion(string, error)
}
task.resume();
}
}
And an example of usage:
func usage() {
GlobalClass.sendInfo("url", data: "data") { (answer, errorCode) in
// your answer and errorCode here
// handle the result
}
}
static func sendInfo(url: String, data: String, completion: (answer: String, errorCode: Int32) -> ()){
//Your code..
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding);
res = (responseString as? String)!;
completion(answer: res, errorCode: err)
}
task.resume()
}
Then when you call the sendInfo, call like so:
sendInfo(url: "your url", data: "your data") { (result, error) in
//you use your result and error values as u want.
}