从服务器存储解码 JSON 数组的位置以及如何在 viewControllers 中全局访问它?

Where to store Decoded JSON array from server and how to access it globally in viewControllers?

目前我正在创建从我的服务器解析 JSON 的应用程序。我可以从服务器接收带有 JSON 模型的数组。 此数组中的数据必须填充到 table 视图中。 我的问题很简单:如果我想从我的应用程序中的多个视图控制器访问它,从服务器存储解码数组的位置?

这是我的 JSON 模型,来自服务器。

import Foundation

struct MyModel: Codable {
    var settings: Test?
    var provider: [Provider]
}

extension MyModel {
    struct setting: Codable {
        var name: String
        var time: Int
    }
}


这是我解码的方式

import Foundation

enum GetResourcesRequest<ResourceType> {
    case success([ResourceType])
    case failure
}

struct ResourceRequest<ResourceType> where ResourceType: Codable {

    var startURL = "https://myurl/api/"
    var resourceURL: URL



    init(resourcePath: String) {
        guard let resourceURL = URL(string: startURL) else {
            fatalError()
        }
        self.resourceURL = resourceURL.appendingPathComponent(resourcePath)
    }


    func fetchData(completion: @escaping
        (GetResourcesRequest<ResourceType>) -> Void ) {
        URLSession.shared.dataTask(with: resourceURL) { data, _ , _ in
            guard let data = data else { completion(.failure)
                return }
            let decoder = JSONDecoder()
            if let jsonData = try? decoder.decode([ResourceType].self, from: data) {
                completion(.success(jsonData))
            } else {
                completion(.failure)
            }
            }.resume()
        }
    }

如果你真的想避免重复加载 data() 调用,最简单的选择是在第一次解析数据后将其缓存在磁盘上(CoreData、Realm、File 等)。

然后每ViewController需要数据的,就可以查询你的存储系统。

当然,这种方法的缺点是您必须编写额外的代码来管理数据的一致性,以确保它在您的应用程序中得到妥善管理。

这是一个 CategoriesProvider 的例子。它仅存储类别 in-memory,您可以在整个应用程序中使用它们。这不是最好的方法,也不是最好的架构,但上手很简单。

class CategoriesProvider {
    static let shared = CategoriesProvider()

    private(set) var categories: [Category]?

    private let categoryRequest = ResourceRequest<Category>(resourcePath: "categories")
    private let dataTask: URLSessionDataTask?

    private init() {}

    func fetchData(completion: @escaping (([Category]?) -> Void)) {
        guard categories == nil else {
            completion(categories)
            return
        }

        dataTask?.cancel()

        dataTask = categoryRequest.fetchData { [weak self] categoryResult in
            var fetchedCategories: [Category]?

            switch categoryResult {
            case .failure:
                print("error")
            case .success(let categories):
                fetchedCategories = categories
            }

            DispatchQueue.main.async {
                self?.categories = fetchedCategories
                completion(fetchedCategories)
            }
        }
    }
}

我建议使用 URLSessionDataTask 来取消之前的任务。当您接连多次调用 fetchData 时,可能会发生这种情况。您必须修改您的 ResourceRequest 和 URLSession.shared.dataTask(...)

的 return 值

这里有更多关于数据任务的详细信息https://www.raywenderlich.com/3244963-urlsession-tutorial-getting-started#toc-anchor-004(DataTask 和 DownloadTask)

现在您可以通过这种方式获取 CategoriesViewController 中的类别:

private func loadTableViewData() {
    CategoriesProvider.shared.fetchData { [weak self] categories in
        guard let self = self, let categories = categories else { return }
        self.categories = categories
        self.tableView.reloadData()
    }
}

在其他视图控制器中,您可以执行相同的操作,但可以在获取之前检查 'categories'。

if let categories = CategoriesProvider.shared.categories {
    // do something
} else {
    CategoriesProvider.shared.fetchData { [weak self] categories in
        // do something
    }
}

在任何 class 之外创建一个全局字典数组,以便在每个 viewcontroller.

上访问它