-1

I have this function recovering the player score from a MySQL database. From other tutorials, I have found the URLSession approach useful when sending data out from the app, but would I be able to actually use the return of the function anywhere? Kept searching for something like a

task.resume() 
task.end()
return (rank, name, score)

?

func downloadLocalScores(_ choice: Int) -> ([String], [String], [String]) {
    var url: URL
    let id: String = getUserID("id")
    if choice == 0 {
        url = NSURL(string: "myPHPscript.php")! as URL
    } else {
        url = NSURL(string: "myPHPscript2.php")! as URL
    }
    let request = NSMutableURLRequest(url: url)
    request.httpMethod = "POST"
    let postString = "id=\(id)"
    request.httpBody = postString.data(using: String.Encoding.utf8)
    var name: [String] = []
    var score: [String] = []
    var rank: [String] = []
    if Reachability().isInternetAvailable() == true {
        let task = URLSession.shared.dataTask(with: request as URLRequest) {
            data, response, error in
            if error == nil {
                let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
                let variables = try! JSONSerialization.jsonObject(with: data! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
                for i in 0..<variables.count {
                    let level = variables[i] as! [String:AnyObject]
                    name.append(level["name"] as! String)
                    score.append(level["score"] as! String)
                    rank.append(level["rank"] as! String)
                }
            } else {
                print(error)
            }
        }
        task.resume()
        return (rank, name, score)
    } else {
        return (["NO CONNECTION"], ["0"])
    }
}

I have another function to download scores, but being a request for top scores, doesn't need to take any input from app

func downloadScores(_ choice: Int) -> ([String], [String]) {
var url: URL
if choice == 0 {
     url = NSURL(string: "myPHPscript.php")! as URL
} else {
     url = NSURL(string: "myPHPscript2.php")! as URL
}
let data = NSData(contentsOf: url)
var variables: NSArray = []
if Reachability().isInternetAvailable() == true {
    variables = try! JSONSerialization.jsonObject(with: data! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray

    var name: [String] = []
    var score: [String] = []

    for i in 0..<variables.count {
        let level = variables[i] as! [String:AnyObject]
        name.append(level["name"] as! String)
        score.append(level["score"] as! String)
    }
    return (name, score)
} else {
    return (["No connection"], [""])
}

}

I am still not perfectly familiar with other options of sending data out of my app, so could the last function be adapted to POST? Have tried something last night but got stuck at data = NSData asking for a type URL instead of the NSMutableURLRequest I had.

Should mention I created global variables and append inside first function, but the result is recovered after they are used and I can't find a way to delay or refresh once they have been filled. I don't mind app waiting for them, as they are used after the viewDidLoad().

Alex Ioja-Yang
  • 1,428
  • 13
  • 28
  • It's not that you can't have a "returned" value with NSURLSession, it's just that you are trying to bypass the asynchronous system. You can bypass it, but it's not recommended. Just keep using closure. The thing is not using async' stuff, should block the current thread, and usually, it's the main one, and it's blocking the UI (quite ugly). Also, `NSData(contentsOf:)` is performing a GET, not a POST. – Larme Feb 16 '17 at 16:04
  • What is your question exactly? – alecnash Feb 16 '17 at 16:13

2 Answers2

0

You cant return because a network requests happen asychronously. Instead of using a return, use a closure that is called when the request has completed. Check out the following:

func sendRequest(_ _request:URLRequest, completion:@escaping (_ success:Bool,_ error:Error?, _ _data:[String:AnyObject]?)->Void) -> URLSessionDataTask {
    let session:URLSession = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: self.queue)
    let task:URLSessionDataTask = session.dataTask(with: _request) { (_data, _response, _error) in
        if let resultsDic:[String:AnyObject] = self.parseJSONFromData(retrievedData, withInitalKey: self.getInitialKey()){
            completion(true, nil, resultsDic)
        } else {
            completion(false, nil, nil)
        }
    }
    task.resume()
    return task
}
Andrew McKinley
  • 1,137
  • 1
  • 6
  • 11
0

I created a small example to show the difference between the input, return, and async completion. Paste this into your playground and experiment.

You'll see the 'passed in' prints first.

Followed by the return.

And last the completion when the async has finished.

import UIKit
import PlaygroundSupport
import Foundation

func getStuffFromServer(_ passedIn: String, completion: @escaping (_ completion: String)->()) -> String {

    print(passedIn)

    PlaygroundPage.current.needsIndefiniteExecution = true

    URLSession.shared.dataTask(with: URL(string: "http://stackoverflow.com")!) {
    result in

        completion("I've completed")

        PlaygroundPage.current.finishExecution()

    }.resume()

    let returnValue = "I'm being returned"
    print(returnValue)
    return returnValue
}

let returned = getStuffFromServer("I'm passed in", completion: { completion in
    print(completion)
})
Frankie
  • 11,508
  • 5
  • 53
  • 60