在 URLSession.shared.dataTask 期间存储来自异步闭包的数据
Storing data from an asynchronous closure during URLSession.shared.dataTask
我尝试了两种技术来从完成处理程序中获取数据和填充数组。在这两种方法中,dataArray 计数都显示为 0。而我能够放置断点并看到当执行在闭包内时正在填充数组:
尝试的第一个方法:
在下面的代码中,dataArray 显示计数为零,即使它在执行内部和外部 completionHandler 期间填充 dataArray。
class ViewController: UIViewController {
var dataArray = []
var urlOuter = URL(string: "outer.url.com/json")
override func viewDidLoad() {
super.viewDidLoad()
self.downloadTask()
print(dataArray.count)
}
func downloadTask() {
let outerTask = URLSession.shared.dataTask(with: urlOuter!, completionHandler: {
(data, response, error) in
let parsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
for arr in parsedData! {
var urlInner = URL(string: "http://inner.url/" + arr["url"] + ".com/json")
let innerTask = URLSession.shared.dataTask(with: urlInner!, completionHandler: {
(data, response, error) in
let innerParsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
self.dataArray.append(innerParsedData)
})
innerTask.resume()
}// end of for loop
})
outerTask.resume()
}
}
尝试的第二种方法:
protocol MyDelegate{ func didFetchData(data:String)}
class ViewController: UIViewController {
var dataArray = []
var urlOuter = URL(string: "outer.url.com/json")
override func viewDidLoad() {
super.viewDidLoad()
self.downloadTask()
print(dataArray.count)
}
func didFetchData(data:String) {
self.dataArray.append(data)
}
func downloadTask() {
let outerTask = URLSession.shared.dataTask(with: urlOuter!, completionHandler: {
(data, response, error) in
let parsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
for arr in parsedData! {
var urlInner = URL(string: "http://inner.url/" + arr["url"] + ".com/json")
let innerTask = URLSession.shared.dataTask(with: urlInner!, completionHandler: {
(data, response, error) in
let innerParsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! String
self. didFetchData(data:innerParsedData)
})
innerTask.resume()
}// end of for loop
})
outerTask.resume()
}}}
请帮助我了解如何从闭包中获取数据并将它们存储在数组中。建议的其他解决方案是使用委托,这就是我在方法 2 中尝试的方法。谢谢。
在异步方法中调用填充数组后,您正在 viewDidLoad
方法中查询数组。
检查 didFetchData()
第二种方法的结果。
override func viewDidLoad() {
super.viewDidLoad()
self.downloadTask()
}
func didFetchData(data:String) {
self.dataArray.append(data)
// Check the count here!!
print(dataArray.count)
}
您需要将协议更改为:
protocol MyDelegate{ func didFetchData(dataArray: [])}
然后为委托添加变量:
var mDelegate = MyDelegate?
然后分配你的结果:
func didFetchDataCompeleted(dataArray: []) {
// hand over the data to the delegate
mDelegate?.didFetchData(self.dataArray)
}
现在将关闭代码中 innerTask
完成时的调用更改为
self.didFetchDataCompeleted(dataArray:self.dataArray)
或直接致电:
self.mDelegate?.didFetchData(self.dataArray)
当 innerTask
完成时
我没有仔细看,但你似乎正确地附加到数组。你出错的地方是过早地要求计数。 URL 请求是 运行 异步的,并且从 CPU 的角度来看需要很长时间:
self.downloadTask() // this function run async
print(dataArray.count) // nothing has been downloaded yet
试试这个:
func downloadTask(completionHandler: () -> Void) {
let outerTask = URLSession.shared.dataTask(with: urlOuter!) { data, response, error in
let parsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
let group = DispatchGroup()
for arr in parsedData! {
var urlInner = URL(string: "http://inner.url/" + arr["url"] + ".com/json")
group.enter()
let innerTask = URLSession.shared.dataTask(with: urlInner!) { data, response, error in
let innerParsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
// Appending to an array concurrently from multiple queues can lead to
// weird error. The main queue is serial, which make sure that the
// array is appended to once at a time
DispatchQueue.main.async {
self.dataArray.append(innerParsedData)
}
group.leave()
}
innerTask.resume()
}// end of for loop
// Make sure all your inner tasks have completed
group.wait(timeout: .forever)
completionHandler()
}
outerTask.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
self.downloadTask() {
print(dataArray.count)
}
}
我尝试了两种技术来从完成处理程序中获取数据和填充数组。在这两种方法中,dataArray 计数都显示为 0。而我能够放置断点并看到当执行在闭包内时正在填充数组:
尝试的第一个方法:
在下面的代码中,dataArray 显示计数为零,即使它在执行内部和外部 completionHandler 期间填充 dataArray。
class ViewController: UIViewController {
var dataArray = []
var urlOuter = URL(string: "outer.url.com/json")
override func viewDidLoad() {
super.viewDidLoad()
self.downloadTask()
print(dataArray.count)
}
func downloadTask() {
let outerTask = URLSession.shared.dataTask(with: urlOuter!, completionHandler: {
(data, response, error) in
let parsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
for arr in parsedData! {
var urlInner = URL(string: "http://inner.url/" + arr["url"] + ".com/json")
let innerTask = URLSession.shared.dataTask(with: urlInner!, completionHandler: {
(data, response, error) in
let innerParsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
self.dataArray.append(innerParsedData)
})
innerTask.resume()
}// end of for loop
})
outerTask.resume()
}
}
尝试的第二种方法:
protocol MyDelegate{ func didFetchData(data:String)}
class ViewController: UIViewController {
var dataArray = []
var urlOuter = URL(string: "outer.url.com/json")
override func viewDidLoad() {
super.viewDidLoad()
self.downloadTask()
print(dataArray.count)
}
func didFetchData(data:String) {
self.dataArray.append(data)
}
func downloadTask() {
let outerTask = URLSession.shared.dataTask(with: urlOuter!, completionHandler: {
(data, response, error) in
let parsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
for arr in parsedData! {
var urlInner = URL(string: "http://inner.url/" + arr["url"] + ".com/json")
let innerTask = URLSession.shared.dataTask(with: urlInner!, completionHandler: {
(data, response, error) in
let innerParsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! String
self. didFetchData(data:innerParsedData)
})
innerTask.resume()
}// end of for loop
})
outerTask.resume()
}}}
请帮助我了解如何从闭包中获取数据并将它们存储在数组中。建议的其他解决方案是使用委托,这就是我在方法 2 中尝试的方法。谢谢。
在异步方法中调用填充数组后,您正在 viewDidLoad
方法中查询数组。
检查 didFetchData()
第二种方法的结果。
override func viewDidLoad() {
super.viewDidLoad()
self.downloadTask()
}
func didFetchData(data:String) {
self.dataArray.append(data)
// Check the count here!!
print(dataArray.count)
}
您需要将协议更改为:
protocol MyDelegate{ func didFetchData(dataArray: [])}
然后为委托添加变量:
var mDelegate = MyDelegate?
然后分配你的结果:
func didFetchDataCompeleted(dataArray: []) {
// hand over the data to the delegate
mDelegate?.didFetchData(self.dataArray)
}
现在将关闭代码中 innerTask
完成时的调用更改为
self.didFetchDataCompeleted(dataArray:self.dataArray)
或直接致电:
self.mDelegate?.didFetchData(self.dataArray)
当 innerTask
完成时
我没有仔细看,但你似乎正确地附加到数组。你出错的地方是过早地要求计数。 URL 请求是 运行 异步的,并且从 CPU 的角度来看需要很长时间:
self.downloadTask() // this function run async
print(dataArray.count) // nothing has been downloaded yet
试试这个:
func downloadTask(completionHandler: () -> Void) {
let outerTask = URLSession.shared.dataTask(with: urlOuter!) { data, response, error in
let parsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
let group = DispatchGroup()
for arr in parsedData! {
var urlInner = URL(string: "http://inner.url/" + arr["url"] + ".com/json")
group.enter()
let innerTask = URLSession.shared.dataTask(with: urlInner!) { data, response, error in
let innerParsedData = try JSONSerialization.jsonObject(with: content, options: .mutableContainers) as! [[String: Any]]
// Appending to an array concurrently from multiple queues can lead to
// weird error. The main queue is serial, which make sure that the
// array is appended to once at a time
DispatchQueue.main.async {
self.dataArray.append(innerParsedData)
}
group.leave()
}
innerTask.resume()
}// end of for loop
// Make sure all your inner tasks have completed
group.wait(timeout: .forever)
completionHandler()
}
outerTask.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
self.downloadTask() {
print(dataArray.count)
}
}