为什么我的完成处理程序不能与URLSession一起使用?

时间:2018-07-17 11:55:38

标签: swift xcode urlsession

我的应用程序遇到了一个小问题。在粘贴任何代码之前,让我提供一些上下文。我有一些动态单元格的TableView。每个单元格包含一个按钮。当我按下单元格中的按钮时,将调用一个函数,该函数发出URLSession datatask请求。我使用Decodable类存储JSON结果,而我要做的就是打印结果数组的计数。我有问题;在返回结果之前进行打印。

为解决该问题,我尝试使用完成处理程序并在DispatchGroup中运行URLSession,直到DispatchGroup结束才打印。

我希望有人可以快速看一下我的代码并指出我的错误。

这是我发出URLSession请求的函数:

func loadLocalPrice(selectedItemName: String, completion: @escaping (_ result: [PriceModel])-> Void) {

    var localPrice = [PriceModel]()

    let urlApi = "http://my.url.com/category/"+self.selectedCategory+"/"+selectedItemName

    guard let url = URL(string: urlApi) else {return completion(localPrice)}

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else {return}
        self.dispatchGroupLoadItems.enter()
        do {
            localPrice = try JSONDecoder().decode([PriceModel].self, from: data)
            print("The result inside the function is: \(localPrice.count)")
        } catch let JSONerror {
            print("error decoding JSON", JSONerror)
        }
        self.dispatchGroupLoadItems.leave()

        }.resume()
        return completion(localPrice)
}

这里是调用包含URLSession的上述函数的函数:

    func addToBasket(sender: UIButton, name: String?, category: String?) {
    var localPrice = [PriceModel]()

    DispatchQueue.main.async {
        self.loadLocalPrice(selectedItemName: name!) {
            (result: [PriceModel]) in
            print("got back inside the dispatchGroup: \(result.count)")

            localPrice = result
        }


        self.dispatchGroupLoadItems.notify(queue: .main) {
            print("Got back outside the dispatchGroup: \(localPrice.count)")
        }
    }
}

下面是我的控制台输出,因此您可以看到返回结果的顺序:

got back inside the dispatchGroup: 0
Got back outside the dispatchGroup: 0
The result inside the function is: 1

3 个答案:

答案 0 :(得分:1)

您不需要调度组并返回此处。

 func loadLocalPrice(selectedItemName: String, completion: @escaping (_ result: [PriceModel])-> Void) {

      var localPrice = [PriceModel]()

      let urlApi = "http://my.url.com/category/"+self.selectedCategory+"/"+selectedItemName

      guard let url = URL(string: urlApi) else {
           completion(localPrice)
           return
      }

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else {
            completion(localPrice)
            return
        }
        do {
            localPrice = try JSONDecoder().decode([PriceModel].self, from: data)
            print("The result inside the function is: \(localPrice.count)"  
        } catch let JSONerror {
            print("error decoding JSON", JSONerror)
        }
        completion(localPrice)
    }.resume()
}

答案 1 :(得分:1)

问题是您正在尝试return completion(localPrice)。 首先,URLSession.shared.dataTask(with: url)在后​​台运行,因此您无需使用dispatchGroupLoadItems

您所要做的就是在completion block URLSession.shared.dataTask(with: url)的主线程上调用completion block,就像这样:

func loadLocalPrice(selectedItemName: String, completion: @escaping (_ result: [PriceModel])-> Void) {
    var localPrice = [PriceModel]()
    let urlApi = "http://my.url.com/category/"+self.selectedCategory+"/"+selectedItemName
    guard let url = URL(string: urlApi) else {
        completion(localPrice)
        return
    }

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else {return}
        do {
            localPrice = try JSONDecoder().decode([PriceModel].self, from: data)
            print("The result inside the function is: \(localPrice.count)")
        } catch let JSONerror {
            print("error decoding JSON", JSONerror)
        }

        DispatchQueue.main.async {
            completion(localPrice)
        }
    }.resume()
}

addToBasket函数将变为:

func addToBasket(sender: UIButton, name: String?, category: String?) {
    var localPrice = [PriceModel]()

    self.loadLocalPrice(selectedItemName: name!) {(result: [PriceModel]) in
        print("The result from completion block: \(result.count)")

        localPrice = result
    }
}

答案 2 :(得分:1)

当您已经有完成处理程序时,您只是不需要dispatchGroup。您可以按照以下正确方式使用completion处理程序来解决您的问题,

func loadLocalPrice(selectedItemName: String, completion: @escaping (_ result: [PriceModel])-> Void) {

    var localPrice = [PriceModel]()

    let urlApi = "http://my.url.com/category/"+self.selectedCategory+"/"+selectedItemName

    guard let url = URL(string: urlApi) else { 
              completion(localPrice)
              return 
            }

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else {
               completion(localPrice)
               return
             }
        do {
            localPrice = try JSONDecoder().decode([PriceModel].self, from: data)
        } catch let JSONerror {
            print("error decoding JSON", JSONerror)
        }
        DispatchQueue.main.async {
          completion(localPrice)
        }
     }.resume() 
}

func addToBasket(sender: UIButton, name: String?, category: String?) {
    var localPrice = [PriceModel]()

    self.loadLocalPrice(selectedItemName: name!) {
        (result: [PriceModel]) in
        print("Count: \(result.count)")
        localPrice = result
    }
}