异步API调用在变量初始化之前不返回数据

时间:2017-11-19 01:23:57

标签: swift api asynchronous

我正在从初始视图到第二视图。第一个视图包含一个文本字段,供用户输入其搜索字词(帐户名称)。该名称被引诱到第二个视图。

然后,我接受此名称,并拨打Riot API,返回其帐户的详细信息(姓名,ID,帐户ID,级别等)。

然后我用他们的凭证(名称,ID,级别)更新GUI标签。

现在是这个过程分崩离析的地方;程序不会等待API调用在它向前移动之前完成。

我想要的步骤分解基本上是按此顺序:

1)使用segue中的搜索词来调用Riot API

2)使用凭据

更新GUI

3)使用Riot API返回的凭据初始化一些变量

相反,这种情况正在发生:

1)使用segue中的搜索词来调用Riot API

2)初始化一些变量(使用来自API的凭证(但它不能,因为它们尚未返回))

3)使用凭证

更新GUI

程序正在向前跳过,而不是等待返回数据。 我已经明白这种调用API的方式是'异步',并且它不会等待数据在继续之前被检索 - 并且DispatchQueue.main.async {}只要其他所有内容都是有用的你需要在大括号内进行编码。

如果在task.resume()之后附加代码,它将不会使用从调用中检索到的数据,因为它尚未返回。

我的问题基本上是:如何让'let task = UrlSession.shared ... task.resume()等待用户凭据,这样我就可以按顺序继续执行其余的代码 - 而不是在DispatchQueue.main.async {}大括号中嵌入此视图的其余部分?

import UIKit

class ViewControllerProfile: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

//test to see if we got the name from the segue:
print("from Segue: " + summonerName)

//execute on view load:
let theUser = Summoner(name: summonerName)
print(theUser.name!)




//API - Summoners Details By Summoner Name:


//Construct request for name in secondViewController(PROFILE)
let root:String = "https://euw1.api.riotgames.com"
let entryPoint:String = "/lol/summoner/v3/summoners/by-name/"
let key:String = "?api_key=<key>"
//theUser.name! is a search term (players name)
let completeURL = root + entryPoint + theUser.name! + key
let urlRecieved = URL(string: completeURL.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!)



let task = URLSession.shared.dataTask(with: urlRecieved!){ (data, response, error) in
    if error != nil{
        print("ERROR")
    }
    else{
        if let content = data{
            do{
                //Array:
                let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:Any]

                //We now extract the required information from the JSON output with keys:
                //Class generics for future parsing:
                let summonerID = myJson["id"] as? UInt64
                let usersSummonerID:Int = Int(summonerID!)
                print(usersSummonerID)

                let accountID = myJson["accountId"] as? UInt64
                let usersAccountID = Int(accountID!)
                print(usersAccountID)

                //Required elements for Profile Labels:
                let extractName = myJson["name"] as? String
                let extractLevel = myJson["summonerLevel"] as? UInt64
                //We need to convert the extractLevel variable from UInt64 to String to update a label without an optional:
                let usersLevel:String = "\(extractLevel!)"

//We update the gui now using the data we got from the API call:
            DispatchQueue.main.async {
                //We dispatch the user interface updates to the main thread here:
                self.summonerLevelLbl.text = ("Level: " + "\(usersLevel)")
                self.summonerNameLbl.text = extractName

                //We dispatch the api-returned userObject's attributes to the main thread for assignment here:
                self.summonerNameMain = extractName!
                self.summonerIDMain = usersSummonerID
                self.accountIDMain = usersAccountID

                print("dispatch completed\n\n")

                //all future code goes here?

            }


            }

            catch{
                print("SOMETHING WENT WRONG WITH SERIALIZATION OF NAME X")
            }
        }
    }
}
task.resume()




theUser.name = summonerNameMain
theUser.accountID = accountIDMain
theUser.summonerID = summonerIDMain


print("ASSIGNMENT TEST")
print(theUser.name!)
print(theUser.summonerID!)
print(theUser.accountID!)
}

@IBOutlet weak var summonerNameLbl: UILabel!

@IBOutlet weak var summonerRankLbl: UILabel!

@IBOutlet weak var summonerLevelLbl: UILabel!




override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

//For Segue:
var summonerName = String()

//For Parsing:
var accountIDMain = Int()
var summonerIDMain = Int()
var summonerNameMain = String()




}

class Summoner:NSObject{

var name:String?
var summonerID:Int?
var accountID:Int?
var matchID:Int?

init(name: String){
    self.name = name

}

}

在task.resume()之后 我希望它在继续之前等待上面的代码完成(让task = URLSession.shared.dataTask ...直到task.resume()) 需要进一步调用需要先前调用数据的API调用,最好还是希望避免在异步中嵌入更多代码。

1 个答案:

答案 0 :(得分:1)

只需移动这些行(如果需要,还可以移动打印语句):

theUser.name = summonerNameMain
theUser.accountID = accountIDMain
theUser.summonerID = summonerIDMain

您对所有未来代码&#34;。

的评论

完成。