(Swift)在for循环中使用带有NSURLSession的信号量

时间:2017-07-12 16:02:34

标签: ios swift semaphore nsurlsession

我目前正在尝试从for循环中的多个GET请求下载数据,然后将其添加到表视图中。 我成功获取数据,但我遇到的问题是主线程在从请求中下载所有数据之前一直运行,因此它没有加载到表视图中。 我试图使用信号量尝试一次运行一个线程但它似乎没有工作。 这是代码:

for item in array{
    let http = item["http"] as! String
    let URL = NSURL(string: http)
    let Request = NSMutableURLRequest(url: URL! as URL)
    Request.setValue(self.headerVal, forHTTPHeaderField: "Authorization")
    Request.httpMethod = "GET"
    let UrlSession = URLSession.shared
    let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
        if error != nil{
            print(error!)
            return;
        }
        else{
            do{
                let ResponseData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
                guard let results = ResponseData["data"] as? [Any] else {
                    print("Couldnt get response from \(http)")
                    return
                }
                let Result = results[0] as! [String:Any]
                self.result.append(Result)
            }
            catch{
                print(error)
            }
        }
    }
    Info.resume()

}
print("finished")
self.tableView.reloadData()

我如何制作它,以便在请求的所有数据完成下载后我可以刷新我的tableview?

2 个答案:

答案 0 :(得分:0)

我认为最佳解决方案是使用Operation所以使用此Operation子类,请调整headerVal类型,我不知道类型

import UIKit

class GetAllData: Operation {

    //1
    var headerVal : String = "" //I don't know the type of headerVal
    var arrayOfDicts : [[String:Any]] = [[:]]
    var allDataResult : [[String:Any]] = []
    var finishedClosure : (([[String:Any]],Error?)->Void)?
    let sema = DispatchSemaphore(value: 0)
    var error : Error?
    //2
    //I don't know the type of headerVal
    init(headerVal:String,arrayOfDicts:[[String:Any]]) {
        super.init()
        self.arrayOfDicts = arrayOfDicts
        self.headerVal = headerVal
    }

    override func cancel() {
        self.sema.signal()
    }

    override func main() {
        self.geAllData()
    }

    func geAllData()
    {
        //4
        if self.isCancelled {
            return
        }

        for item in self.arrayOfDicts{

            let http = item["http"] as! String
            let URL = NSURL(string: http)
            let Request = NSMutableURLRequest(url: URL! as URL)
            Request.setValue(self.headerVal, forHTTPHeaderField: "Authorization")
            Request.httpMethod = "GET"
            let UrlSession = URLSession.shared
            let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
                if error != nil{
                    print(error!)
                }
                else{
                    do{
                        let ResponseData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
                        guard let results = ResponseData["data"] as? [Any] else {
                            print("Couldnt get response from \(http)")
                            return
                        }
                        let Result = results[0] as! [String:Any]
                        self.allDataResult.append(Result)
                    }
                    catch{
                        print(error)
                        self.sema.signal()
                    }
                }
                self.sema.signal()
            }
            Info.resume()

            _ = self.sema.wait(timeout: DispatchTime.distantFuture)
        }
        print("finished")

        if(self.finishedClosure != nil)
        {
            DispatchQueue.main.async {
                self.finishedClosure!(self.allDataResult, nil)
            }
        }

        //7
        if self.isCancelled {
            return
        }

    }


}

使用

self.getAllDataOperation = GetAllData(headerVal: "Your headerVal Here", arrayOfDicts: yourArrayItems)
        self.getAllDataOperation!.finishedClosure = { [weak self] (results,error) in
            self?.results = results
            self?.tableView.reloadData()
        }
        let OperationQ = OperationQueue()
        OperationQ.addOperation(self.getAllDataOperation!)

希望这有帮助,让我知道如果能解决你的问题

答案 1 :(得分:0)

信号量是一种方式,但DispatchGroup可能是更好的方式。

 let downloadGroup = DispatchGroup()
 for item in array{
  ...
 downloadGroup.enter()
let Info = UrlSession.dataTask(with: Request as URLRequest) { (data, response, error) -> Void in
  ...
  downloadGroup.leave()
  }   
 }   

 downloadGroup.notify(queue: DispatchQueue.main) { // 2
   //callback
 }