为什么我的完成处理程序不能与我的 URLSession 一起工作?
Why isn't my completion handler working with my URLSession?
我 运行 在我的应用程序中遇到了一个小问题。在我粘贴任何代码之前,让我提供一些上下文。我有一个带有一些动态单元格的 TableView。每个单元格都包含一个按钮。当我按下单元格内的按钮时,将调用一个函数来发出 URLSession 数据任务请求。我使用 Decodable class 来存储 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
这里不需要调度组和return。
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()
}
问题是您正在尝试 return completion(localPrice)
。
首先,URLSession.shared.dataTask(with: url)
在后台是 运行,所以你不需要使用 dispatchGroupLoadItems
。
您所要做的就是在 URLSession.shared.dataTask(with: url)
completion block
的主线程上调用您的 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
}
}
当您已经有了完成处理程序时,您就不需要 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
}
}
我 运行 在我的应用程序中遇到了一个小问题。在我粘贴任何代码之前,让我提供一些上下文。我有一个带有一些动态单元格的 TableView。每个单元格都包含一个按钮。当我按下单元格内的按钮时,将调用一个函数来发出 URLSession 数据任务请求。我使用 Decodable class 来存储 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
这里不需要调度组和return。
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()
}
问题是您正在尝试 return completion(localPrice)
。
首先,URLSession.shared.dataTask(with: url)
在后台是 运行,所以你不需要使用 dispatchGroupLoadItems
。
您所要做的就是在 URLSession.shared.dataTask(with: url)
completion block
的主线程上调用您的 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
}
}
当您已经有了完成处理程序时,您就不需要 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
}
}