Swift 3 - 使用DispatchGroup()等待每个URL会话的完成?

时间:2017-04-29 04:39:20

标签: swift asynchronous swift3 synchronous

嗨所以我有这个问题,我有一个数组填充字符串(例如:[狗,猫,girraffe,牛]),我将使用此ID对某些网站进行API调用以获取图像从该网站。我需要结果与数组的顺序相同。

对于这个例子,我需要输出是这样的,如果我打印两个数组,它应该是这样的: theString - dog,cat,girraffe,cow

年龄 - 5,10,20,5< - 排序对应动物

但相反,我得到的年龄输出如下: 年龄 - 5岁,20岁,10岁,5岁或

年龄 - 10岁,20岁,5岁,5岁等

我几乎不得不对骰子起作用,直到我得到输出为准。

因为每个API调用都是异步的,所以当涉及到年龄时,排序总是随机的。我已经被困在这个问题好几天了,不太确定如何去做..

示例代码:

let theString = ["dog", "cat", "girraffe", "cow"]
var age = Array<Int>() // to store the ages of the animal in order



override func viewDidLoad() {
    super.viewDidLoad()
     //make the call 4 times
    for each in theString{
      doAPICall(name:each)
      print(age)//the output is not in order 
    }


}


func doAPICall(name: String){

  let animal = name
  let urlString:String = "https://somewebsite.com/api/"+ animal

    let url = URL(string: urlString)!

    let task = URLSession.shared.dataTask(with: url, completionHandler: {
        (data, response, error) in

        if error != nil {

            print(error!.localizedDescription)

        } else{
            do{

                let parsedData = try JSONSerialization.jsonObject(with: data!, options: []) as! [String:Any]
                let age = parsedData["age"] as! Int
                self.age.append(age) //appends the age to the array

            } catch let error as NSError {
                print(error)
            }
        }//end else

    })
    task.resume()
}

简而言之,我需要一些方法来告诉for循环或异步调用等到上一个完成之后再转到下一个

2 个答案:

答案 0 :(得分:0)

我建议您先使用age值初始化nil

var age = [Int?](repeating: nil, count: theString.count)

然后,在每次调用完成后,将右侧索引处的值设置为您获得的结果。

    } else{
        do{

            let parsedData = try JSONSerialization.jsonObject(with: data!, options: []) as! [String:Any]
            let age = parsedData["age"] as! Int

            // Note these lines!
            if let index = theString.index(of: animal) {
                self.age[index] = age
            }

        } catch let error as NSError {
            print(error)
        }
    }//end else

答案 1 :(得分:0)

试试这个!

let theString = ["dog", "cat", "girraffe", "cow"]
var age = Array<Int>() // to store the ages of the animal in order

override func viewDidLoad() {
    super.viewDidLoad()
     //make the call 4 times
    for each in theString{
      doAPICall(animal: each,completion: { (responseArray,error) -> () in
           let age = responseArray["age"] as! Int
           if let index = theString.index(of: each) {
            self.age[index] = age
          }
        })
      print(age)//the output is in order 
    }
}
func doAPICall(animal: String,completion:@escaping (_ responsedata:NSDictionary?_ error:NSError?) -> Void){

  let Baseurl = "https://somewebsite.com/api/"+ animal
  let RequestUrl = URL(string: Baseurl)
  let request = NSMutableURLRequest(url: RequestUrl!)
  let semaphore = DispatchSemaphore(value: 0)
  let task = session.dataTask(with: request as URLRequest) { (data, response, error) in

  guard error == nil && data != nil else {
            print("error=\(error?.localizedDescription)")
            return
        }
        if let httpStatus = response as? HTTPURLResponse{
            if httpStatus.statusCode != 200 {
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(response)")
            }
        }
        do {
            let ResponseDictionary = try JSONSerialization.jsonObject(with: data! as Data, options: .allowFragments) as! as! NSDictionary?
            completion(ResponseDictionary,nil)
            semaphore.signal()
        }
        catch let error as NSError {
            print("Details of JSON parsing error:\n \(error.localizedDescription)")
            completion(nil,error)
        }
    }
    task.resume()
    _ = semaphore.wait(timeout: .distantFuture)
}