我正在从初始视图到第二视图。第一个视图包含一个文本字段,供用户输入其搜索字词(帐户名称)。该名称被引诱到第二个视图。
然后,我接受此名称,并拨打Riot API,返回其帐户的详细信息(姓名,ID,帐户ID,级别等)。
然后我用他们的凭证(名称,ID,级别)更新GUI标签。
现在是这个过程分崩离析的地方;程序不会等待API调用在它向前移动之前完成。
我想要的步骤分解基本上是按此顺序:
1)使用segue中的搜索词来调用Riot API
2)使用凭据
更新GUI3)使用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调用,最好还是希望避免在异步中嵌入更多代码。
答案 0 :(得分:1)
只需移动这些行(如果需要,还可以移动打印语句):
theUser.name = summonerNameMain
theUser.accountID = accountIDMain
theUser.summonerID = summonerIDMain
您对所有未来代码&#34;。
的评论完成。