我正在编写一个应用程序,需要查看本地JSON文件,然后将其版本与我在网站上托管的版本进行比较。如果它们不匹配,请从网上下载并保存到本地。如果它们确实匹配,则继续并使用本地JSON文件。这个版本信息在JSON文件中。
以前,我的应用程序只需分析在线数据并直接使用。然后它将使用JSON数据填充UITableView。现在我正在使用本地文件,UITableView没有被填充,我不确定如何修复它。通过阅读新函数,我认为我的问题是我没有使用JSONDecoder(),而是使用JSONSerialization(),因此我不能将它指向我想要的特定元数据。
18年6月26日编辑(下面是我的BonusListViewController.swift文件):

//
//  BonusListViewController.swift
//  Tour of Honor
//
//  Created by Tommy Craft on 6/6/18.
//  Copyright © 2018 Tommy Craft. All rights reserved.
//

import UIKit
import os.log
import Foundation

class BonusListViewController: UITableViewController {

    var bonuses = [JsonFile.JsonBonuses]()

    let defaults = UserDefaults.standard

    override func viewDidLoad() {
        super.viewDidLoad()

        // MARK: Data Structures
        // Settings Struct
        struct Constants {
            struct RiderData {
                let riderNumToH = "riderNumToH"
                let pillionNumToH = "pillionNumToH"
            }
            struct RallyData {
                let emailDestinationToH = "emailDestinationToH"
            }
        }

        //MARK: Check for updated JSON file
        checkJSON()

        //MARK: Trigger JSON Download
        /*
        downloadJSON {
            print("downloadJSON Method Called")
        }
        */
    }
    // MARK: - Table View Configuration
    // MARK: Table view data source
    override func numberOfSections(in tableView: UITableView) -> Int {
        print("Found \(bonuses.count) sections.")
        return bonuses.count
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("Found \(bonuses.count) rows in section.")
        return bonuses.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
        cell.textLabel?.text = bonuses[indexPath.section].name.capitalized
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "showDetail", sender: self)
    }
    // MARK: - Table View Header
    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 30
    }
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return bonuses[section].state
    }
    override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 3
    }

    // MARK: Functions
    // MARK: - Download JSON from ToH webserver

    func downloadJSON(completed: @escaping () -> ()) {
        let url = URL(string: "http://tourofhonor.com/BonusData.json")
        URLSession.shared.dataTask(with: url!) { [weak self] (data, response, error) in
            if error == nil {
                do {
                    let posts = try JSONDecoder().decode(JsonFile.self, from: data!)
                    DispatchQueue.main.async {
                        completed()
                    }
                    print("Downloading Updated JSON (Version \(posts.meta.version))")
                    print(posts.bonuses.map {$0.bonusCode})
                    print(posts.bonuses.map {$0.state})
                    self?.bonuses = posts.bonuses
                    self?.defaults.set("downloadJSON", forKey: "jsonVersion") //Set version of JSON for comparison later
                    DispatchQueue.main.async {
                        //reload table in the main queue
                        self?.tableView.reloadData()
                    }
                } catch {
                    print("JSON Download Failed")
                }
            }
        }.resume()
    }


    func checkJSON() {
        //MARK: Check for updated JSON file
        let defaults = UserDefaults.standard
        let hostedJSONFile = "http://tourofhonor.com/BonusData.json"
        let jsonURL = URL(string: hostedJSONFile)
        var hostedJSONVersion = ""
        let jsonData = try! Data(contentsOf: jsonURL!)
        let jsonFile = try! JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as! [String : Any]
        let metaData = jsonFile["meta"] as! [String : Any]
        hostedJSONVersion = metaData["version"] as! String
        let localJSONVersion = defaults.string(forKey: "jsonVersion")
        if localJSONVersion != hostedJSONVersion {
            print("L:\(localJSONVersion!) / H:\(hostedJSONVersion)")
            print("Version Mismatch: Retrieving lastest JSON from server.")
            updateJSONFile()
        } else {
            //Retrieve the existing JSON from documents directory
            print("L:\(localJSONVersion!) / H:\(hostedJSONVersion)")
            print("Version Match: Using local file.")
            let fileURL = defaults.url(forKey: "pathForJSON")
            do {
                let localJSONFileData = try Data(contentsOf: fileURL!, options: [])
                let myJson = try JSONSerialization.jsonObject(with: localJSONFileData, options: .mutableContainers) as! [String : Any]
                //Use my downloaded JSON file to do stuff
                print(myJson)
                DispatchQueue.main.async {
                    //reload table in the main queue
                    self.tableView.reloadData()
                }
            } catch {
                print(error)
            }
        }
    }

    func updateJSONFile() {
        print("updateJSONFile Method Called")
        let hostedJSONFile = "http://tourofhonor.com/BonusData.json"
        let jsonURL = URL(string: hostedJSONFile)
        let itemName = "BonusData.json"
        let defaults = UserDefaults.standard
        do {
            let directory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
            let fileURL = directory.appendingPathComponent(itemName)
            let jsonData = try Data(contentsOf: jsonURL!)
            let jsonFile = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String : Any]
            let metaData = jsonFile!["meta"] as! [String : Any]
            let jsonVersion = metaData["version"]
            print("JSON VERSION ", jsonVersion!)
            try jsonData.write(to: fileURL, options: .atomic)
            defaults.set(fileURL, forKey: "pathForJSON") //Save the location of your JSON file to UserDefaults
            defaults.set(jsonVersion, forKey: "jsonVersion") //Save the version of your JSON file to UserDefaults
            DispatchQueue.main.async {
                //reload table in the main queue
                self.tableView.reloadData()
            }
        } catch {
            print(error)
        }
    }

    // MARK: - Navigation

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destination = segue.destination as? BonusDetailViewController {
            destination.bonus = bonuses[(tableView.indexPathForSelectedRow?.row)!]
        }
    }
}

下面是JsonFile.swift:
import Foundation

struct JsonFile: Codable {
    struct Meta: Codable {
        let fileName: String
        let version: String
    }
    struct JsonBonuses: Codable {
        let bonusCode: String
        let category: String
        let name: String
        let value: Int
        let city: String
        let state: String
        let flavor: String
        let imageName: String
    }
    let meta: Meta
    let bonuses: [JsonBonuses]
}

这是因为在我的更新版本中没有使用JSONDecoder()还是因为我走错了路?另外,如何让这个新数据与UITableView一起工作?

最佳答案

首先,您错误地解析了JSON值。您需要首先了解JSON格式。转到JSON文件链接,并对其进行分析。如果它以“{”开头,那么它就是一个字典,如果它以“[”开头,那么它就是一个数组。在你的例子中,它是一个字典,然后是字符串(“meta”,“counds”)键。所以,我们知道我们的钥匙是弦。接下来,我们来看看我们的价值观。对于“meta”,我们有一个String:String字典;对于“奖金”,我们有一系列字典。
因此,我们的JSON格式是[String:Any],或者可以编写Dictionary<String, Any>
下一步是访问字典中的这些值。

func updateJSONFile() {
        print("updateJSONFile Method Called")
        let hostedJSONFile = "http://tourofhonor.com/BonusData.json"
        let jsonURL = URL(string: hostedJSONFile)
        let itemName = "BonusData.json"
        let defaults = UserDefaults.standard
        do {
            let directory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
            let fileURL = directory.appendingPathComponent(itemName)
            let jsonData = try Data(contentsOf: jsonURL!)
            let jsonFile = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String : Any]
            let metaData = jsonFile!["meta"] as! [String : Any]
            let jsonVersion = metaData["version"]
            print("JSON VERSION ", jsonVersion!)
            try jsonData.write(to: fileURL, options: .atomic)
            defaults.set(fileURL, forKey: "pathForJSON") //Save the location of your JSON file to UserDefaults
            defaults.set(jsonVersion, forKey: "jsonVersion") //Save the version of your JSON file to UserDefaults
            DispatchQueue.main.async {
                //reload table in the main queue
                self.tableView.reloadData()
            }
        } catch {
            print(error)
        }
    }

然后,当您访问本地保存的文件时,您必须再次解析JSON以检查版本:
func checkJSON() {
        //MARK: Check for updated JSON file
        let defaults = UserDefaults.standard
        let hostedJSONFile = "http://tourofhonor.com/BonusData.json"
        let jsonURL = URL(string: hostedJSONFile)
        var hostedJSONVersion = ""
        let jsonData = try! Data(contentsOf: jsonURL!)
        let jsonFile = try! JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as! [String : Any]
        let metaData = jsonFile["meta"] as! [String : Any]
        hostedJSONVersion = metaData["version"] as! String
        let localJSONVersion = defaults.string(forKey: "jsonVersion")
        if localJSONVersion != hostedJSONVersion {
            print("\(localJSONVersion) : \(hostedJSONVersion)")
            updateJSONFile()
        } else {
            //Retrieve the existing JSON from documents directory
            print("\(localJSONVersion) : \(hostedJSONVersion)")
            print("Local JSON is still the latest version")
            let fileUrl = defaults.url(forKey: "pathForJSON")
            do {
                let localJSONFileData = try Data(contentsOf: fileUrl!, options: [])
                let myJson = try JSONSerialization.jsonObject(with: localJSONFileData, options: .mutableContainers) as! [String : Any]
                //Use my downloaded JSON file to do stuff

                DispatchQueue.main.async {
                    //reload table in the main queue
                    self.tableView.reloadData()
                }
            } catch {
                print(error)
            }
        }
    }

不要忘记在Info.plist文件中允许任意加载,因为JSON文件托管在没有https的网站上。
json - 读取本地JSON文件并使用它来填充UITableView-LMLPHP

关于json - 读取本地JSON文件并使用它来填充UITableView,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50942306/

10-17 01:30