【问题标题】:How to get an array from URLSession如何从 URLSession 获取数组
【发布时间】:2019-11-30 08:04:57
【问题描述】:

尝试为新闻网站制作程序。我通过 api 从网站获取信息,一切正常。

唯一的问题是,如何让这个数组脱离循环?

这是我的代码:

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()
    }
}

【问题讨论】:

    标签: ios arrays swift swift5.1


    【解决方案1】:
    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))"
        }
    }
    

    在您的类中声明新闻数组并在 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()
    }
    

    【讨论】:

    • 我在我的控制器中添加了 var news:[News] = [] 和结构,我尝试通过这个命令 print(news) 进行打印,我将得到 "[ ]"
    • 在“getUser”方法完成后打印“newsData”数组。
    • 我也调用 getUsers() 并在打印数组但结果为 first
    • 结构不应该在你的视图控制器内部,它应该在你的视图控制器类之外。如果可能,请分享您在获取用户方法中调用的 URL。
    • 我把 struct 放在另一个文件中,然后我把 func getUser 放在 viewcontroller 中的所有类之后,var news:[News] = [] 放在 viewcontroller 中,更多在 func viewDidLoad() 我调用 getUser()然后我打印(新闻)(class ViewController: UIViewController { var news:[News] = [] override func viewDidLoad() { super.viewDidLoad() getUsers() print(news) } } func getUsers(){ }
    【解决方案2】:

    根本问题是您正在异步检索数据(例如,getUsers 将使用URLSession 从网络发起一个相对较慢的请求,但会立即返回)。因此这是行不通的:

    override func viewDidLoad() {
        super.viewDidLoad()
        getUsers()
    
        print(news)
    }
    

    在检索到 news 之前,您正在从 getUsers 返回。所以news 仍然是[]

    解决方案是给getUsers一个“completion handler”,一个参数,你可以在其中指定异步请求完成时应该执行什么代码:

    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()
    }
    

    然后您的视图控制器可以获取消息,传递一个“闭包”,即说明异步调用完成时要做什么的代码。在这种情况下,它将设置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)
        }
    

    【讨论】:

      猜你喜欢
      • 2021-12-26
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-04
      • 1970-01-01
      • 1970-01-01
      • 2019-03-01
      相关资源
      最近更新 更多