如何从URLSession获取数组

问题描述 投票:0回答:2

[试图为新闻网站制作程序。我通过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
2个回答
0
投票
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()
}

0
投票

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

override func viewDidLoad() {
    super.viewDidLoad()
    getUsers()

    print(news)
}

您正在检索getUsers之前从news返回。因此news仍为[]

解决方案是为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()
}

然后,您的视图控制器可以获取新闻,并传递一个“闭包”,即表示异步调用完成后该怎么做的代码。在这种情况下,它将设置self.news并触发必要的UI更新(例如,刷新表视图):

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)
    }
© www.soinside.com 2019 - 2024. All rights reserved.