0

I'm trying to post from swift to php and then return json encoded data back to swift.

However, print(task.response) is nil. My link does what it is supposed to but my app still responds with nil. Any idea why?

let request = NSMutableURLRequest(URL: NSURL(string: "https://www.flashkase.com/API/createAccount.php")!)
request.HTTPMethod = "POST"
let postString = "username=frogg222"
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
    }

    if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 { // check for http errors
        print("statusCode should be 200, but is \(httpStatus.statusCode)")
        print("response = \(response)")
    }

    let responseString = String(data: data!, encoding: NSUTF8StringEncoding)
    print("responseString = \(responseString)")
}
task.resume()
print(task.response)

And my PHP file

<?php 
include($_SERVER["DOCUMENT_ROOT"] . "/inc/database.php");
$arr = [];

$arr[] = 'Reporting for duty';

if($_SERVER['REQUEST_METHOD'] == 'POST'){
    $arr[] = 'Post received';
    $arr[] = $_POST['username'];
}

echo json_encode($arr);
?>

Update: How can I check for data after completion? If I uncomment sleep(3) it will display results...but that's obviously not ideal.

func postToServer(postURL: String, postString: String) {

    let request = NSMutableURLRequest(URL: NSURL(string: postURL)!)
    request.HTTPMethod = "POST"
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
        data, response, error in 

        print("\(data), \(response), \(error)")

    }
    task.resume()
    //sleep(3)
}


let sendURL: String = "https://www.flashkase.com/API/createAccount.php"
let sendData: String = "username=frogg222&email=fake123@gmail.com&password=fake1234"

postToServer(sendURL,postString: sendData)
Trevor Wood
  • 1,805
  • 1
  • 24
  • 42

1 Answers1

1

dataTaskWithRequest is an asynchronous operation. Printing the response code immediately after the task starts will obviously print nil, as it hasn't had time to get a value. The completion handler already has a response object you can use, so inside your completion handler, call print(response) to see the properties and try to get a response code.

Andy Ibanez
  • 11,317
  • 8
  • 63
  • 94
  • I'm kind of new to swift, which is the completion handler? and/or how can I make one? – Trevor Wood Sep 18 '16 at 20:33
  • Your completion handler is everything the `dataTaskWithRequest(request) {...}` (where `...` is your code). – Andy Ibanez Sep 18 '16 at 20:34
  • I'm sorry man, it's still not working. Any chance you can provide an example? I placed `sleep(3)` before `print(task.response)` and it finally gave me the response but no data. – Trevor Wood Sep 18 '16 at 20:40
  • `sleep(3)` worked because you gave the network operation enough time to complete and to have a response code before calling `print`. That is not an ideal solution. You could just put it above `guard error == nil && data != nil else {`. – Andy Ibanez Sep 18 '16 at 20:42
  • I've updated my post, I still can't figure out how to check after completion, can you provide an example please? – Trevor Wood Sep 18 '16 at 21:11
  • Right, I forgot a small detail and that is that the completion handler does include a `response` for you. Inside your completion handler you can just try to `print(response)` – Andy Ibanez Sep 18 '16 at 21:12
  • I can't seem to find the original `print(task.response)` in your edited question so I'm not sure what I am looking at now. A good way to figure these things out is to print all callblack parameters - response, data, error - at the beginning of the completion handler to see what they have. – Andy Ibanez Sep 18 '16 at 21:15
  • I just updated my question. The code I posted there doesn't return anything. It won't allow me to place task.reponse inside of task – Trevor Wood Sep 18 '16 at 21:21
  • Yeah that makes sense. You can just print the response provided in the handler but I see you are already doing that. Just print the three variables in the callback at the very beginning of it to see what you get. – Andy Ibanez Sep 18 '16 at 21:22
  • I'm not sure what you mean. Can you provide an example please? – Trevor Wood Sep 18 '16 at 21:31
  • `print("\(data), \(response), \(error)")` at the beginning of your callback. – Andy Ibanez Sep 18 '16 at 21:34
  • without sleep(3) it returns nothing. – Trevor Wood Sep 18 '16 at 21:35
  • Where are you putting that print? At the beginning of the callback like I said or outside of it? Because that's the symptom of this not being called inside the callback like I said. I have already told you what the callback is. Put that print inside of it. – Andy Ibanez Sep 18 '16 at 21:37
  • Recommended reading: [Closures in Swift](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html). At this point our commentary does not have to do with your question and your problem is simply lack of understanding of how closures (commonly used as callbacks) work. Read that chapter, and if possible (and strongly recommended), the whole book before dwelling any further. – Andy Ibanez Sep 18 '16 at 21:40
  • thanks! I'll check it out I've updated above what my code looks like now. – Trevor Wood Sep 18 '16 at 21:41