To start off, I want to say that I am new to using JSON, so if this code needs some cleanup also, let me know. So I am trying to update json file. I have created an empty jsonfile named data.json
in my project, inside a folder I named Data. The file looks like this:
{
"fullname": "Testuser2",
"answered": 0,
"correct": 0
}
This is my JSONData.swift
:
import Foundation
struct UserData: Codable {
let fullname: String
let answered: Int
let correct: Int
}
struct GlobalVariable{
static var fullname = String()
static var answered = Int()
static var correct = Int()
}
These function to read the json file:
private func readLocalFile(forName name: String) -> Data? {
do {
if let bundlePath = Bundle.main.path(forResource: name,
ofType: "json"),
let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {
return jsonData
}
} catch {
print(error)
}
return nil
}
private func parse(jsonData: Data) {
do {
let decodedData = try JSONDecoder().decode(UserData.self,
from: jsonData)
GlobalVariable.fullname = decodedData.fullname
GlobalVariable.answered = decodedData.answered
GlobalVariable.correct = decodedData.correct
} catch {
print("decode error")
}
}
And this is how I use it:
func getJSON() {
if let localData = self.readLocalFile(forName: "data") {
self.parse(jsonData: localData)
print(GlobalVariable.fullname)
print(GlobalVariable.answered)
print(GlobalVariable.correct)
}
}
So the getJSON
successfully shows me the correct values.
Now after the GlobalVariable.answered
and GlobalVariable.correct
has been incrementet, I want to save it.
This is the code I am trying to use to save it:
func saveJSON {
print("---------")
print(GlobalVariable.fullname)
print(GlobalVariable.answered)
print(GlobalVariable.correct)
print("---------")
let dataToUpdate = [UserData(fullname: GlobalVariable.fullname, answered: GlobalVariable.answered, correct: GlobalVariable.correct)]
do {
let jsonData = try JSONEncoder().encode(dataToUpdate)
let jsonString = String(data: jsonData, encoding: .utf8)!
print(jsonString)
if let documentDirectory = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first {
let pathWithFilename = documentDirectory.appendingPathComponent("data.json")
do {
try jsonString.write(to: pathWithFilename,
atomically: true,
encoding: .utf8)
} catch {
// Handle error
}
}
} catch { print(error) }
}
The three print
codes inside saveJSON
shows the correct value, but someone nothing gets saved to the json file. The json file stays untouched.. How come?
I've also tried removing the .json
from let pathWithFilename = documentDirectory.appendingPathComponent("data.json")
, but still not working..
CodePudding user response:
You are starting with your data.json
in your bundle.
You read that, change the values, and then write it to Documents
folder.
So, when you want to read the file, you need to first see if it exists in the Documents folder. If so, read it from there. If it doesn't exist (e.g. first time the app is run), then read it from the bundle.
CodePudding user response:
you can read from the local file in the main bundle but you couldn't write on it,
get documents folder:
private func documentsFolder() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentDirectory = paths[0] as String
return documentDirectory
}
// load data code
private mutating func loadData() {
let filePath = documentsFolder().appending("/filename.data")
let fileManager = FileManager.default
if fileManager.fileExists(atPath: filePath) {
print("FILE AVAILABLE")
lists = load()
} else {
//load json file
lists = loadFromBundle()
//saved words list in documents directory
save(lists ?? [])
}
}
///loading data from file created in documents directory with name "filename.data"
func load<O:Codable>() -> O? {
let url = URL(fileURLWithPath: documentsFolder().appending(path.rawValue))
guard let data = try? Data(contentsOf: url) else { return nil }
do {
return try JSONDecoder().decode(O.self, from: data)
} catch {
print(error)
}
return nil
}
//// initially load from main bundle to get initial values or whatever
private func loadFromBundle() -> [ListModel]? {
var arr = [ListModel]()
let url = Bundle.main.url(forResource: "Lists", withExtension: "json")!
do {
let data = try Data(contentsOf: url)
let json = try JSONDecoder().decode([ListModel].self, from: data)
arr = json
}
catch {
print("Error occured during Parsing", error)
}
return arr
}
//// saving data in new file created and this file will be loaded again to read from.
func save<O: Codable>(_ object: O) {
let url = URL(fileURLWithPath: documentsFolder().appending(path.rawValue))
guard let data = try? JSONEncoder().encode(object.self) else { return }
do {
try data.write(to: url)
} catch {
print(error)
}
}