how do I array from a GET request function in view

2019-06-03 20:18发布

问题:

I'm very new to swift, so I will probably have a lot of faults in my code but what I'm trying to achieve is send a GET request to a server with paramters inside a function. I want to use the array I receive from the server in my viewdidload and in other functions but cant seem to find a way to store the array so i can use it. in my function it is filled, but out of my function it is empty

var scenarioArray: Array<Any> = []


let idPersoon = UserDefaults.standard.object(forKey: "idPersoon") as! String

override func viewDidLoad() {
super.viewDidLoad()
ScenarioArray()
print(scenarioArray)
print(self.scenarioArray)
}
func ScenarioArray()  {

    var request = URLRequest(url: URL(string: "http://dtsl.ehb.be/app&web/ios_php/getAllScenariosByPersoon.php?persoonID="+idPersoon)!)
    request.httpMethod = "GET"
    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)")
            return
        }
        do {
            if let jsonResult = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
                self.scenarioArray = (jsonResult["Scenarios"] as! NSArray) as! Array<Any>
                print("ASynchronous\(self.scenarioArray)")

            }
        } catch let error as NSError {
            print(error.localizedDescription)
            }



    }
    task.resume()
}

回答1:

Your "problem" is that you are trying to GET data from a server, meaning that you are doing a network call.

Now...you don't know how long that network call will take when you launch it, if you are on a good network then it might be fast, but if you are on 3G network it might take a while.

If the call to your server was done synchronously, the result would be that each and every time you'd try to fetch data your code would focus on doing just that, meaning that nothing else would go on... that is not what you want :)

Instead, when you use URLSession, and call task.resume() that method is executed asynchronously, meaning that it starts on another thread in the background where it will fetch data.

In the meantime, your main thread is free to handle UI rendering and so on. At some point in the near future your network call finishes and you now have valid data and must inform whoever needs to know.

So when you do a call to dataTask(with: completionHandler:), what you are actually saying is something along the lines of:

"hey...go fetch this data in the background please, and when you're done, I'd like to execute the code I've passed you here in the completionHandler with the parameters you tell me about".

Hope that makes just a little sense :)

Now...you have this code:

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)")
        return
    }
    do {
        if let jsonResult = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
            self.scenarioArray = (jsonResult["Scenarios"] as! NSArray) as! Array<Any>
            print("ASynchronous\(self.scenarioArray)")

        }
    } catch let error as NSError {
        print(error.localizedDescription)
    }
}

That last part of the function call ({ data, response, error in...) is the completionHandler, which is not executed straight away. It is not executed until the retrieval of data has completed.

And therefore when you do a call to your ScenarioArray() function in viewDidLoad, what will happen is that the asynchronous call to fetch data will start in the background and your viewDidLoad will continue what it is doing, meaning that when you say:

print(scenarioArray)
print(self.scenarioArray)

then you can not expect scenarioArray to be populated yet as your task is busy fetching that data in the background.

So...what you need to do, as @vadian says, is to update your UI once the data has been fetched, meaning, in the completionHandler.

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)")
        return
    }
    do {
        if let jsonResult = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
            self.scenarioArray = (jsonResult["Scenarios"] as! NSArray) as! Array<Any>
            print("ASynchronous\(self.scenarioArray)")
            //Now you have data, reload the UI with the right scenarioArray
        }
    } catch let error as NSError {
        print(error.localizedDescription)
    }
}

Hope that makes sense and helps you.