简体   繁体   中英

Save custom struct in Flat file

Following is the custom structure. I wanted to store the array of custom structures that is [details]. Am not able to store [details] in file. While writing this [details in file, application is crashing 'invalid json format'

struct details : Identifiable {
    let id  = UUID()
    var name : String?
    var time : String?
    var msg : [MsgDetails]?
    var loc : String?
    var type : String?
}

Write in the file: msgArray is array of details. msgArray = [details].

extension Array {
    var jsonStringRepresentation: String? {
        let jsonData = try? JSONSerialization.data(withJSONObject: self, options: [])
        guard jsonData != nil else {return nil}
        let jsonString = String(data: jsonData!, encoding: .utf8)
        guard jsonString != nil else {return nil}
        return jsonString! as String

    }
}

In the below code NSKeyedArchiver.archivedData is returning nil

if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first{
            let fileURL = dir.appendingPathComponent(self.fileName)
            let data = try? NSKeyedArchiver.archivedData(withRootObject: msgArray.jsonStringRepresentation!, requiringSecureCoding: true)
            do {
                try data!.write(to: fileURL)
            } catch let error {
                print("\(error.localizedDescription)")
            }
        }

You could use Codable instead of NSKeyedArchiver to convert models to data and write to file. Assuming that your model contains only basic types, all you have to do is conform to Codable protocol.

struct Details : Identifiable, Codable {
    ...
}

Write to file:

extension Array where Element: Encodable {

    func saveToFile(fileName: String) throws {
        do {
            let data = try JSONEncoder().encode(self)
            if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
                let fileURL = dir.appendingPathComponent(fileName)
                try data.write(to: fileURL)
            } else {
                //throw some error
            }
        } catch {
            throw error
        }
    }

}

Saved file can be read like this:

func readFile(fileName: String) throws {
    do {
        if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
            let url = dir.appendingPathComponent(fileName)
            let data = try Data(contentsOf: url)
            let decoded = try JSONDecoder().decode([Details].self, from: data)
            print("decoded: ", decoded)
        } else {
            //throw some error
        }
    } catch {
        throw error
    }

}

If you can replace the UIImage in your model with its Data , Codable conformance can be achieved automatically. Get the imageData from UIImage using image.pngData() .

struct MsgDetails: Codable {
    var imageData: Data?
    var text: String?
    var date: Date?

    var image: UIImage? {
        if let data = imageData {
            return UIImage(data: data)
        }
        return nil
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM