[英]How to get an array from URLSession
Trying to make a program for a news site.试图为新闻网站制作程序。 I take information from the site through the api, everything works fine.
我通过 api 从站点获取信息,一切正常。
The only question is, how do I get this array out of the loop?唯一的问题是,如何让这个数组脱离循环?
Here is my code:这是我的代码:
import UIKit
class ViewController: UIViewController {
var news:[News] = []
override func viewDidLoad() {
super.viewDidLoad()
getUsers()
print(news)
}
func getUsers() {
guard let url = URL(string: "http://prostir.news/swift/api2.php") else {return}
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
do {
news = try JSONDecoder().decode([News].self, from: data)
// print(self.news)
} catch let error {
print(error)
}
}
}.resume()
}
}
There is no loop, you have to add a loop 没有循环,您必须添加一个循环
struct News{
let href: String
let site: String
let time: String
}
var newsData = [News]()
...
do {
guard let jsonArray = try JSONSerialization.jsonObject(with: dataResponse) as? [[String: Any]] else { return }
for item in jsonArray {
if let href = item["href"] as? String,
let site = item["site"] as? String,
let time = item["time"] as? String {
self.newsData.append(News(href: href, site: site, time:time))
}
}
} catch {
print("Error", error)
}
struct News:Codable, CustomStringConvertible{
let href:String?
let site:String?
let title:String?
let time:String?
var description: String {
return "(href:- \(href), site:- \(site), title:- \(title), time:- \(time))"
}
}
Declare news array in your class and assign the response to this array in getUsers method在您的类中声明新闻数组并在 getUsers 方法中将响应分配给该数组
var news:[News] = []
func getUsers(){
guard let url = URL(string: "https") else {return}
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
do {
self.news = try JSONDecoder().decode([News].self, from: data)
print(self.news)
} catch let error {
print(error)
}
}
}.resume()
}
The fundamental problem is you are retrieving data asynchronously (eg getUsers
will initiate a relatively slow request from the network using URLSession
, but returns immediately).根本问题是您正在异步检索数据(例如,
getUsers
将使用URLSession
从网络发起一个相对较慢的请求,但会立即返回)。 Thus this won't work:因此这行不通:
override func viewDidLoad() {
super.viewDidLoad()
getUsers()
print(news)
}
You are returning from getUsers
before the news
has been retrieved.您正在检索
news
之前从getUsers
返回。 So news
will still be []
.所以
news
仍然是[]
。
The solution is to give getUsers
a “completion handler”, a parameter where you can specify what code should be performed when the asynchronous request is done:解决方案是给
getUsers
一个“完成处理程序”,一个参数,你可以指定当异步请求完成时应该执行什么代码:
enum NewsError: Error {
case invalidURL
case invalidResponse(URLResponse?)
}
func getUsers(completion: @escaping (Result<[News], Error>) -> Void) {
let queue = DispatchQueue.main
guard let url = URL(string: "http://prostir.news/swift/api2.php") else {
queue.async { completion(.failure(NewsError.invalidURL)) }
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
queue.async { completion(.failure(error)) }
return
}
guard
let data = data,
let httpResponse = response as? HTTPURLResponse,
200 ..< 300 ~= httpResponse.statusCode
else {
queue.async { completion(.failure(NewsError.invalidResponse(response))) }
return
}
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let news = try decoder.decode([News].self, from: data)
queue.async { completion(.success(news)) }
} catch let parseError {
queue.async { completion(.failure(parseError)) }
}
}.resume()
}
Then your view controller can fetch the news, passing a “closure”, ie code that says what to do when the asynchronous call is complete.然后你的视图控制器可以获取消息,传递一个“闭包”,即说明异步调用完成后要做什么的代码。 In this case, it will set
self.news
and trigger the necessary UI update (eg maybe refresh tableview):在这种情况下,它将设置
self.news
并触发必要的 UI 更新(例如可能刷新 tableview):
class ViewController: UIViewController {
var news: [News] = []
override func viewDidLoad() {
super.viewDidLoad()
fetchNews()
}
func fetchNews() {
getUsers() { result in
switch result {
case .failure(let error):
print(error)
case .success(let news):
self.news = news
print(news)
}
// trigger whatever UI update you want here, e.g., if using a table view:
//
// self.tableView.reloadData()
}
// but don't try to print the news here, as it hasn't been retrieved yet
// print(news)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.