使用本地 json 文件中的数据更新 swift UI 中的列表

Posted

技术标签:

【中文标题】使用本地 json 文件中的数据更新 swift UI 中的列表【英文标题】:update a list in swift UI with data from a local json file 【发布时间】:2019-10-19 12:23:43 【问题描述】:

我有一个函数,使用 for 循环实现一个名为“data”的本地 json 文件获取一些数据并将这些数据传递给“DataModel”类型的数组“storage”,最后所有内容都已保存()使用函数 save()

直到这里看起来一切正常,因为如果我使用 storage.count 打印我的存储中有多少数据,如果我打印从 json 文件读取的数据并传递到我的存储数组,则数据量会增加,所有数据都是在那里。

一旦我按下按钮并显示所有从 json 准备好的数据,我希望在 swiftUI 中更新我的列表

为了调试,我尝试创建一个通过 2 个文本框和 save() 加载数据的函数 .. 这工作正常,我添加了我的新值,保存和列表自动更新。

这是我的数据模型

import Foundation

class DataModel:Identifiable , Codable 

    var nameApt : String
    var icaoCode : String

init(nameApt: String, icaoCode: String) 
    self.nameApt = nameApt
    self.icaoCode = icaoCode


这是我的数据管理器

import UIKit
import Combine
class DataManager :ObservableObject 
let objectWillChange = PassthroughSubject<Void,Never>()

    var storage : [DataModel] = []
    typealias Storage = [DataModel]

    var filePath : String = ""

    init()  caricaDati() 
    func caricaDati() 
        // creiamo il percorso al file
        filePath = cartellaDocuments() + "\test.plist"

        // usiamo NSFileManager per sapere se esiste un file a quel percorso
        if FileManager.default.fileExists(atPath: filePath) 

            // se c'è de-archiviamo il file di testo nell'array
            // serve il blocco do try catch
            do 
                // proviamo a caricare il file dal percorso creato in precedenza
                let data = try Data(contentsOf: URL(fileURLWithPath: filePath))
                // creiamo il decoder
                let decoder = PropertyListDecoder()
                // proviamo a decodificare il file nell'array
                storage = try decoder.decode(Storage.self, from: data)
             catch 
                // se non ce la fa scriviamo in console l'errore
                debugPrint(error.localizedDescription)
            

         else 
            let tem = DataModel(nameApt: "NewDasmi", icaoCode: "DAMI")
            storage = [tem]
            salva()
        
    

    func salva() 
        objectWillChange.send()
        let encoder = PropertyListEncoder()
        encoder.outputFormat = .xml // impostiamo l'output corretto
        // serve il blocco do try catch
        do 
            // proviamo a codificare l'array
            let data = try encoder.encode(storage)
            // proviamo a salvare l'array codificato nel file
            try data.write(to: URL(fileURLWithPath: filePath))
         catch 
            // se non ce la fa scriviamo in console l'errore
            debugPrint(error.localizedDescription)
        

    

    // for debugging this function in order to see if my list update with manual insertion

    func creaData (nomeApt: String, icao: String) 
        let temporVar = DataModel(nameApt: nomeApt, icaoCode: icao)
        self.storage.append(temporVar)
        salva()
    

    func open (fileName : String) 
        if let path = Bundle.main.path(forResource: fileName, ofType: "json") 
            do 
                let fileUrl = URL(fileURLWithPath: path)
                let datafile = try Data(contentsOf: fileUrl,options: .mappedIfSafe)
                let json = JSON(data:datafile)


                let caricaDati = DataModel(nameApt: "TEST", icaoCode: "TEST")
                var i =  0
                for _ in 0...json.count 
                    caricaDati.nameApt = json[i]["airportName"].stringValue
                    caricaDati.icaoCode = json[i]["airportCode"].stringValue
                    i=i+1
                    objectWillChange.send() 
                    self.storage.append(caricaDati)
                    print(caricaDati.nameApt)
                    print(caricaDati.icaoCode)
                
                salva()
                print(storage.count) //  count of item in array storage


            catch 
                print("erroree")
            

        
    
    func cartellaDocuments() -> String 
        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        //print(paths[0])
        return paths[0]
    



这里是我在 SwiftUI 中的界面

import SwiftUI

struct ContentView: View 
    @ ObservedObject var dm : DataManager

    @State var nomeApt : String = ""
    @State var icaoApt : String = ""

    var body: some View 
        VStack 
            HStack 
                TextField("nome", text: $nomeApt)
                TextField("icao", text: $icaoApt)
                Button(action: 

                    // for debugging just to see if the list update automatically with new item manually inserted! and it works...
                    self.dm.creaData(nomeApt: self.nomeApt, icao: self.icaoApt)
                    // not updating with json file
                    self.dm.open(fileName: "data")
                ) 
                    Text(/*@START_MENU_TOKEN@*/"Button"/*@END_MENU_TOKEN@*/)
                
            
            List
                ForEach (dm.storage)  item in
                    HStack 
                        Text(item.nameApt)
                        Spacer()
                        Text(item.icaoCode)
                    

            
            
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView(dm: DataManager())
    


【问题讨论】:

我在open函数里面使用crea data函数解决了。 【参考方案1】:

我通过在函数 open 中使用函数 crea data 解决了

   func creaData (nomeApt: String, icao: String) 
        let temporVar = DataModel(nameApt: nomeApt, icaoCode: icao)
        self.storage.append(temporVar)
        salva()
    

    func open (fileName : String) 
        if let path = Bundle.main.path(forResource: fileName, ofType: "json") 
            do 
                let fileUrl = URL(fileURLWithPath: path)
                let datafile = try Data(contentsOf: fileUrl,options: .mappedIfSafe)
                let json = JSON(data:datafile)
                var i = 0
                for _ in 0...json.count 
                    let caricaDati = DataModel(nameApt: "TEST", icaoCode: "TEST")
                    caricaDati.nameApt = json[i]["airportName"].stringValue
                    caricaDati.icaoCode = json[i]["airportCode"].stringValue
                    creaData(nomeApt: caricaDati.nameApt, icao: caricaDati.icaoCode)
                    i = i+1
                
                salva()
                print(storage.count)



            catch 
                print("erroree")
            

        
    

【讨论】:

以上是关于使用本地 json 文件中的数据更新 swift UI 中的列表的主要内容,如果未能解决你的问题,请参考以下文章

如何使用从 Swift 3 中的滑块中选择的 JSON 数据更新 tableviewcell?

Swift .writeToFile 不会更新 mainBundle 中的 JSON 文件

iOS Swift - URLSessionDataTask 在刷新时没有得到更新的 JSON 数据

解析 JSON 文件(本地存储),从而快速创建对象数组

从 Json 数据中分组,其中包含 Swift 4 中的字典数组

iOS swift 3.0 本地 JSON 解析崩溃