【发布时间】:2018-09-03 19:18:36
【问题描述】:
我有一个函数可以抓取嵌入网站的 JSON 文件并返回一个字符串数组。因为它返回的数据对我的视图控制器来说是必不可少的,所以我需要在视图加载之前运行这个函数。它在视图控制器的初始化中被调用。
func scrapeBuses() -> [String] {
let config = URLSessionConfiguration.default
//config.waitsForConnectivity = true
let defaultSession = URLSession(configuration: config)
let url = URL(string: link to a JSON file)
let request = NSMutableURLRequest(url: url!)
request.cachePolicy = .reloadIgnoringLocalCacheData
var loops = [String]()
let group = DispatchGroup()
group.enter()
DispatchQueue.main.async {
let task = defaultSession.dataTask(with: request as URLRequest) { data, response, error in
do {
print("Getting information from website")
if let error = error {
print(error.localizedDescription)
} else if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 {
print("in async")
loops.append("test2")
}
}
catch { print(error)}
}
}
task.resume()
print("about to return")
//return loops
}
group.wait()
return loops
}
因为它是异步的,所以我添加了 DispatchGroup 和 wait() 语句,以便我的主线程等到这些基本数据被抓取后再继续线程的其余部分。然而,我注意到,当这个视图控制器的 segue 发生时(即,当视图控制器被初始化时)没有任何其他内容被打印并且模拟停止。显然这意味着主线程正在等待scrape() 完成,但是为什么它会无限运行呢?当我在我的网络浏览器和 Rested 中访问该网站时,我可以看到它正确地托管了 JSON。
编辑:
我尝试了使用完成处理程序而不是DispatchQueue.wait() 的同一函数的另一个版本。下面是代码:
func scrapeBuses(completion: @escaping ([String]) -> Void) {
let config = URLSessionConfiguration.default
let defaultSession = URLSession(configuration: config)
let url = URL(string: "https://www.cmunc.net/assets/appData.json")
let request = NSMutableURLRequest(url: url!)
request.cachePolicy = .reloadIgnoringLocalCacheData
var loops = [String]()
let task = defaultSession.dataTask(with: request as URLRequest) { data, response, error in
print("Getting information from website")
if let error = error {
print(error.localizedDescription)
} else if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 {
print("in async")
loops.append("test2")
}
completion(loops)
}
task.resume()
}
这是视图控制器的init调用的函数:
func refresh() {
var newArray = [String]()
scrapeBuses { loops in
newArray = loops
print("calling scrapeBuses closure")
}
print(newArray)
}
使用完成处理程序,代码可以正确执行。 scrapeBuses 中的打印语句和 closeure 中的打印语句。非常感谢所有提供见解的人。
【问题讨论】:
-
我尝试了一个完成处理程序,没有任何改变。请在你的问题中显示你尝试了什么。您很可能在滥用完成处理程序。无论如何永远不要在主线程中等待。
-
请发布有效代码。你有不匹配的花括号。
do/catch是不必要的,因为do块内没有任何东西抛出。 -
请尝试了解异步数据处理的工作原理。您必须将
print(newArray)(或处理数组的真实代码)放入闭包中,因为闭包在refresh完成后稍后执行。跨度> -
正如我所猜测的,您在滥用完成处理程序模式。我猜你知道你通常在
viewDidLoad()方法中设置视图。因为 iOS 在所有视图都准备好设置时调用该方法。同样。您需要在完成处理程序中编写您使用loops的所有内容。因为当您的loops准备好使用时,您更新的代码会调用该方法。 -
您需要从完成处理程序代码中删除
DispatchQueue.main.async {}。
标签: ios swift asynchronous nsurlsession