我正在重构我之前编写的代码,其中使用Alamofire下载了一些Json文件。
第一请求很简单。我发出请求,得到响应,然后解析并将其存储在Realm上。没问题直截了当的东西。
第二个请求有些棘手,因为我需要从第一个JSON请求中检索到的多个ID。
我针对该问题的解决方案是首先在具有Alamofire请求的函数上创建完成处理程序:
func requestData(httpMethod: String, param: Any?, CallType : String, complition: @escaping (Bool, Any?, Error?) -> Void){
我的想法是使用完成功能来等待Alamofire响应完成,然后启动新请求。原来那还行不通。
我能够通过为完成添加延迟来实现这一目标。
DispatchQueue.main.asyncAfter(deadline: .now() + 4)
它确实有效,但是由于多种原因,它并不是一个好的实践,我想用更智能的方法来重构它。
我的问题:
1)如何在同一函数上进行多个JSON请求的最佳方法是什么?一种正确地等待第一个开始第二个等等的方法? 2)现在,我调用一个函数来请求第一个JSON,然后在调用中间进行第二个请求。在我看来,我将第一个请求挂起的时间太长,等待所有请求完成,然后再完成第一个请求。我认为这不是一个好习惯
这是完整的代码。感谢帮助
@IBAction func getDataButtonPressed(_ sender: Any) {
requestData(httpMethod: "GET", param: nil, CallType: "budgets") { (sucess, response, error) in
if sucess{
print("ready")
DispatchQueue.main.asyncAfter(deadline: .now() + 4){
accounts = realm.objects(Account.self)
requestAccounts()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 4){
users = realm.objects(User.self)
requestUser()
}
}
}
}
func requestData(httpMethod: String, param: Any?, CallType : String, complition: @escaping (Bool, Any?, Error?) -> Void){
let url = "https://XPTO.com/v1/\(CallType)"
guard let urlAddress = URL(string: url) else {return}
var request = URLRequest(url: urlAddress)
request.httpMethod = httpMethod
request.addValue("application/json", forHTTPHeaderField: "accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer appKey", forHTTPHeaderField: "Authorization")
if param != nil{
guard let httpBody = try? JSONSerialization.data(withJSONObject: param!, options:[]) else {return}
request.httpBody = httpBody
}
Alamofire.request(request).responseJSON { (response) in
let statusCode = response.response?.statusCode
print("Status Code \(statusCode!)")
jsonData = try! JSON(data: response.data!)
complition(true, jsonData, nil)
if httpMethod == "GET"{
saveJsonResponse(jsonData: jsonData, CallType: CallType)
}
}
}
func requestAccounts(){
var count = accounts.count
while count != 0{
let account = accounts[0]
RealmServices.shared.delete(account)
count -= 1
}
let numberOfBugdets = budgets.count
for i in 0...numberOfBugdets - 1{
requestData(httpMethod: "GET", param: nil, CallType: "/budgets/\(budgets[i].id)/accounts") { (sucess, response, error) in
print("accounts downloaded")
let numberOfAccounts = jsonData["data"]["accounts"].count
for j in 0...numberOfAccounts - 1{
let realm = try! Realm()
do{
try realm.write {
// Code to save JSON data to Realm
realm.add(newAccount)
}
} catch {
print("something")
}
}
}
}
}
func requestUser(){
var count = users.count
while count != 0{
let user = users[0]
RealmServices.shared.delete(user)
count -= 1
}
requestData(httpMethod: "GET", param: nil, CallType: "user") { (success, response, error) in
print("User data downloaded")
let realm = try! Realm()
do{
try realm.write {
// Code to save JSON data to Realm
realm.add(newUser)
}
} catch {
print("something")
}
}
}
func saveJsonResponse(jsonData: JSON, CallType: String){
case "budgets":
var count = budgets.count
while count != 0{
let budget = budgets[0]
RealmServices.shared.delete(budget)
count -= 1
}
let numberOfBudgets = jsonData["data"]["budgets"].count
for i in 0...numberOfBudgets - 1 {
// Code to save JSON data to Realm
RealmServices.shared.create(newBudget)
}
}
答案 0 :(得分:0)
在这种情况下,我建议 completionHandlers 。
这是您的代码片段中如何实现和使用它的方式,试图理解它并在您的代码中实现它。
//CompletionHandlers
func firstOperation(completionHandler: @escaping (_ id: String) -> Void){
//preform alamoFire and in .response { } call completionHandler and pass it the id
completionHandler("10")
}
func buttonClicked () {
firstOperation { (id) in
secondFunction(completionHandler: { (data) in
// your data
})
}
}
func secondFunction(completionHandler: @escaping (_ data: String) -> Void){
//preform alamoFire and in .response { } call completionHandler and pass it the id
completionHandler("some Data")
}
这应该使您对如何实现它有更好的了解,CompletionHandlers功能强大
特别是在处理此类情况时,当您必须执行依赖于其他操作结果的操作时,在网络中,我们无论如何也无法预测操作时间。
了解有关completionHandlers here
的更多信息