ios - Swift:异步 dataTask 永远不会终止
问题描述
我有一个函数可以抓取嵌入在网站中的 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
和闭幕中的打印语句。非常感谢所有提供见解的人。
解决方案
您应该将完成处理程序添加到您的scrapeBuses
func。
func scrapeBuses(completion: ([String]?, Error?) -> Void) {
// etc (remove all mentions of groups)
let task = defaultSession.dataTask(with: request as URLRequest) { data, response, error in
do {
print("Getting information from website")
if let error = error {
DispatchQueue.main.async { // Call back on the main queue
completion(nil, error)
}
} else if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 {
print("in async")
loops.append("test2")
}
DispatchQueue.main.async {
completion(loops, nil)
}
}
catch {
DispatchQueue.main.async {
completion(nil, error)
}
}
}
task.resume()
}
那么……</p>
func viewDidLoad() {
super.viewDidLoad()
scrapeBuses { loops, error in
if let error = error {
print(error)
return
}
// Do something with loops
}
}
推荐阅读
- ansible - 查找文件并添加行 ansible
- ssl - websocket 的 TLS 问题。Binance echange 的 API.Csharp.Client 库
- systemd - Systemd 有服务等待对象注册
- redux - 如何实现redux-toolkit和next,js又不丢SSR
- docker - 删除 docker 容器上的大日志文件后如何回收 ubuntu 主机上的磁盘空间
- amazon-redshift - 无法使用 Epoch 日期转换为红移日期创建自动刷新视图
- c - 警告:导入 unistd.h 后函数“sbrk”的隐式声明
- azure - Azure API 提取
策略的响应状态码 - apache-kafka - Kafka 使用 Confluent Playbooks 从 5.4.1 升级到 6.1.2
- c# - 如何使用 .net core 删除 pfx 证书