After HTTP POST request UIView change delays - ios

I have use this code to make HTTP POST request:
let myURL = NSURL(string: serverURL)
let request = NSMutableURLRequest(URL: myURL!)
request.HTTPMethod = "POST"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print(error)
} else {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(responseString)
self.view.backgroundColor = UIColor.redColor()
}
}
task.resume()
I have experience that the view's backgroundColor changes after several seconds from the print of the responseString.
Why is that and how can I make it simultaniously?
Thanks.

Always perform UI changes on main thread, so change your view's backgrondColor on the main thread like this way.
dispatch_async(dispatch_get_main_queue(),{
self.view.backgroundColor = UIColor.redColor()
}

You need to perform UI changes on the main thread in order to make it faster, Because i think http requests are made asynchronously for example downloading an image. So in your code you can do as follows
dispatch_async(dispatch_get_main_queue(),{
self.view.backgroundColor = UIColor.redColor()
}

Related

iOS Swift 3 - Can't stop the UIActivityIndicatorView after submit

I have a submit button which submits email and password for validation through HTTP in JSON format, but indicator view does not stop even though the app receives the response from the server.
#IBAction func signInButtonAction(_ sender: UIButton) {
let validated = validateEmailAddressTextField()
if validated {
let emailAddress = emailAddressTextField.text
let password = passwordField.text
let url:URL = URL(string: "http://localhost:8080/app/user/signin")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.allHTTPHeaderFields = ["Content-Type": "application/json"]
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let user = User(emailAddress: emailAddress!, password: password!)
let requestJSON = careGiver.toJSON()
request.httpBody = requestJSON?.data(using: String.Encoding.utf8)
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
indicator.center = view.center
view.addSubview(indicator)
indicator.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.0) {
let task = session.dataTask(with: request as URLRequest) {
(
data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("error")
return
}
let dataString = String(data: data, encoding: String.Encoding.utf8)
print(dataString)
indicator.stopAnimating()
}
task.resume()
}
}
}
When I click 'submit' button, I see an indicator view on top of the button, but it doesn't stop and disappear.
Is there anything wrong with the code?
I am using Swift 3 and Xcode 8.
Thanks.
indicator.stopAnimating()
Try to run this line of code on the main thread:
DispatchQueue.main.async {
indicator.stopAnimating()
}
Network closure is called on a random thread, but UI code must be handled in main thread only. So all you need is to call your indicator.stopAnimating() in the main thread:
DispatchQueue.main.async {
indicator.stopAnimating()
}
Also I'd move this block to the beginning of the closure (before guard) to prevent continue of the animation in case of error in response.

PushViewController doesn't work after httpPost

I have made a login screen which takes the input and communicates with the REST api to verify the user. If the response is true, I login the user else not.
I have written a method openViewControllerBasedOnIdentifier(id) to switch views.
The REST api returns true and false appropriately. The push controller gets called but view does not change. How if I place only one line in LoginAction method 'self.openViewControllerBasedOnIdentifier("PlayVC")' and remove the rest of the code , it works fine.
Here is my code
#IBAction func LoginAction(_ sender: Any) {
//self.openViewControllerBasedOnIdentifier("PlayVC")
Constants.login_status = false
//created NSURL
let requestURL = NSURL(string: URL_BK)
//creating NSMutableURLRequest
let request = NSMutableURLRequest(url: requestURL! as URL)
//setting the method to post
request.httpMethod = "POST"
let username = phonenumber.text
//creating the post parameter by concatenating the keys and values from text field
let postParameters = "username="+username!+"&password=bk&schoolId=0";
//adding the parameters to request body
request.httpBody = postParameters.data(using: String.Encoding.utf8)
//creating a task to send the post request
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
let responseData = String(data: data!, encoding: String.Encoding.utf8)
if error != nil{
print("error is \(error)")
return;
}
//parsing the response
do {
print(“Received data is ---%#",responseData as Any)
let myJSON = try JSONSerialization.jsonObject(with: data! , options: .allowFragments) as? NSDictionary
if let parseJSON = myJSON {
var status : Bool!
status = parseJSON["status"] as! Bool?
//print(status)
if status==false
{
Constants.login_status = false
}
else{
Constants.login_status = true
print("calling PLAYVC")
self.openViewControllerBasedOnIdentifier("PlayVC")
}
}
else{
print("NULL VALUE RECEIVED")
}
} catch {
print(error)
}
}
//executing the task
task.resume()
}
You should open the new view controller on the main thread like this:
DispatchQueue.main.async {
self.openViewControllerBasedOnIdentifier("PlayVC")
}
Your REST API query response is processed in a background thread when you call URLSession.shared.dataTask and so when you call any UI actions, you should wrap the code as above to execute the UI code in the main thread. Then it would work fine :)

How to output loading message as NSURL retrieves URL's html?

I am using Swift's NSURL function to retrieve HTML output from a PHP script that interacts with a MySQL database with variables passed with POST and secured with an SSL certificate.
Everything is all fine and great except for the occasional prolonged loading which resulting in a blank table view. Is there any way to run a function while I am waiting for the response string? I am completely in the dark on this one.
Here is the code I am using:
let myUrl = NSURL(string: "http://www.casacorazon.org/ios.html")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
if error != nil {
print("Error: \(error)")
}
dispatch_async(dispatch_get_main_queue()) {
self.testLabel.text = "\(responseString!)"
}
}
}
task.resume()
Yes. You can add a UIActivityIndicatorView to display a loading symbol. And any code you place after task.resume() will run while the network call is happening. Depending if you're already on the main thread or not, you might need an additional dispatch block after it (the same way you do it in your completion callback):
dispatch_async(dispatch_get_main_queue()) {
// make your UIActivityIndicator visible here
}

How to securely pass variables to PHP script from Swift application, or make this code more secure

I am using NSURL to call a PHP script that interacts with with a MySQL database. I am passing the variables through the URL, which can be intercepted and hacked. Is there any way to pass form data with Swift, or securely pass variables to a URL using a similar structure that I have now? I have completed the application only to realize this vulnerability. If there is no way to alter this code, I guess I will have to rewrite a bunch... Here is the structure code I have:
let username = "bob"
let myUrl = NSURL(string: "http://127.0.0.1/phpscript.php?username=\(username)")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
if error != nil {
print("Error: \(error)")
}
dispatch_async(dispatch_get_main_queue()) {
self.testLabel.text = "\(responseString!)"
}
}
}
task.resume()
As you can see, it would be simple to gather the username just by seeing the URL. Do you know of a way to pass variables other than through the URL, without having to rewrite all of this code?Thank you very much
You could pass username through post by adding between ..."POST" and let task... this code:
let postString = "username=\(username)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
end result:
let username = "bob"
let myUrl = NSURL(string: "http://127.0.0.1/phpscript.php")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let postString = "username=\(username)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
if error != nil {
print("Error: \(error)")
}
dispatch_async(dispatch_get_main_queue()) {
self.testLabel.text = "\(responseString!)"
}
}
}
task.resume()

NSURL taking a long time to return URL's contents. Is there a way to speed it up?

I am using NSURL to submit MySQL queries to a web server to store my app's data. Problem is, the request takes around 15 seconds even for a simple 5 word reply. I have made my code as streamlined as possible, but I do not think it has sped up at all.
Code:
import UIKit
import Foundation
class ViewController: UIViewController {
#IBOutlet weak var testLabel: UILabel!
#IBAction func testButton(sender: UIButton) {
let myUrl = NSURL(string: "http://www.casacorazon.org/ios.html")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
self.testLabel.text = "\(responseString!)"
if error != nil {
print("Error: \(error)")
}
}
task.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
If you know of a way to make the code run a bit faster, or trim the 15 seconds down I would love to know.Thanks,Nick
You are networking. You are not in change of the network. That's just how life is. You should not care how long it takes. Your callback method will be called back asynchronously, whenever the network communication finishes. It could be ten minutes from now (well, maybe not, because there would probably be a timeout before that). It is your job to code in such a way that that indeterminate lapse of time is okay.
It might be helpful to run the callback in a prioritized queue. Try this and it would be great if you comment whether or not it made a difference, if not I'll delete the answer and save myself from more embarrassment :)
#IBAction func testButton(sender: UIButton) {
let myUrl = NSURL(string: "http://www.casacorazon.org/ios.html")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
if error != nil {
print("Error: \(error)")
}
dispatch_async(dispatch_get_main_queue()) {
self.testLabel.text = "\(responseString!)"
}
}
}
task.resume()
}

Resources