JSONencoder 不保存新编码的 json 数组 (iOS)
JSONencoder not saving new encoded json array (iOS)
我有一个看起来像这样的 json 文件(在一个名为 list.json 的文件中)
[
{
"id": "C8B046E9-70F5-40D4-B19A-40B3E0E0877B",
"name": "Dune",
"author": "Frank Herbert",
"page": "77",
"total": "420",
"image": "image1.jpg"
},
{
"id": "2E27CA7C-ED1A-48C2-9B01-A122038EB67A",
"name": "Ready Player One",
"author": "Ernest Cline",
"page": "234",
"total": "420",
"image": "image1.jpg"
}
]
这是我的应用程序附带的默认文件(这些是可以删除的示例)。我的内容视图有一个成员变量,它使用我编写的解码函数来获取 json 数组并将其显示在列表中。我想在 json 文件中添加另一本书。该视图将另一个结构附加到数组,然后使用此函数
将新附加的数组编码为 list.json
func writeJSON(_ bookData: [Book]) {
do {
let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("list.json")
let encoder = JSONEncoder()
try encoder.encode(bookData).write(to: fileURL)
} catch {
print(error.localizedDescription)
}
}
按下按钮时在 NewBook 视图中调用此函数。 bookData 是我的内容视图中的解码数组,我在我的 NewBook 视图中使用了绑定。
如果您添加图书并返回到内容视图(列表现在包含附加的结构),代码可以正常工作,但如果您关闭应用程序并再次打开它,列表将使用默认的 json 文件.我认为我的 writeJSON 函数有错误。
另请注意,我尝试在 URL 中将 create 参数更改为 false,但这没有帮助。
编辑:我正在按要求添加 Book 结构
struct Book: Hashable, Codable, Identifiable {
var id: UUID
var name: String
var author: String
var page: String
var total: String
var image: String
}
编辑 2:这是针对 iOS 应用
编辑 3:我的加载数据功能
func load<T: Decodable>(_ filename: String) -> T {
let data: Data
guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
fatalError("Couldn't find \(filename) in main bundle.")
}
do {
data = try Data(contentsOf: file)
} catch {
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}
do {
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
} catch {
fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}
您可能没有覆盖磁盘上的现有文件。在将数据写入磁盘时尝试 options: .atomic
。
func writeJSON(_ bookData: [Book]) {
do {
let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("list.json")
try JSONEncoder().encode(bookData).write(to: fileURL, options: .atomic)
} catch {
print(error)
}
}
edit/update:
这里的问题是您没有将文件保存在您认为应该保存的位置。 Bundle目录为read-only,与你的App文档目录无关
func load<T: Decodable>(_ filename: String) -> T? {
// no problem to force unwrap here you actually do want it to crash if the file it is not inside your bundle
let readURL = Bundle.main.url(forResource: filename, withExtension: "json")!
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let jsonURL = documentDirectory
.appendingPathComponent(filename)
.appendingPathExtension("json")
// check if the file has been already copied from the Bundle to the documents directory
if !FileManager.default.fileExists(atPath: jsonURL.path) {
// if not copy it to the documents (not it is not a read-only anymore)
try? FileManager.default.copyItem(at: readURL, to: jsonURL)
}
// read your json from the documents directory to make sure you get the latest version
return try? JSONDecoder().decode(T.self, from: Data(contentsOf: jsonURL))
}
func writeJSON(_ bookData: [Book]) {
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let jsonURL = documentDirectory
.appendingPathComponent("list")
.appendingPathExtension("json")
// write your json at the documents directory and use atomic option to override any existing file
try? JSONEncoder().encode(bookData).write(to: jsonURL, options: .atomic)
}
我有一个看起来像这样的 json 文件(在一个名为 list.json 的文件中)
[
{
"id": "C8B046E9-70F5-40D4-B19A-40B3E0E0877B",
"name": "Dune",
"author": "Frank Herbert",
"page": "77",
"total": "420",
"image": "image1.jpg"
},
{
"id": "2E27CA7C-ED1A-48C2-9B01-A122038EB67A",
"name": "Ready Player One",
"author": "Ernest Cline",
"page": "234",
"total": "420",
"image": "image1.jpg"
}
]
这是我的应用程序附带的默认文件(这些是可以删除的示例)。我的内容视图有一个成员变量,它使用我编写的解码函数来获取 json 数组并将其显示在列表中。我想在 json 文件中添加另一本书。该视图将另一个结构附加到数组,然后使用此函数
将新附加的数组编码为 list.jsonfunc writeJSON(_ bookData: [Book]) {
do {
let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("list.json")
let encoder = JSONEncoder()
try encoder.encode(bookData).write(to: fileURL)
} catch {
print(error.localizedDescription)
}
}
按下按钮时在 NewBook 视图中调用此函数。 bookData 是我的内容视图中的解码数组,我在我的 NewBook 视图中使用了绑定。
如果您添加图书并返回到内容视图(列表现在包含附加的结构),代码可以正常工作,但如果您关闭应用程序并再次打开它,列表将使用默认的 json 文件.我认为我的 writeJSON 函数有错误。
另请注意,我尝试在 URL 中将 create 参数更改为 false,但这没有帮助。
编辑:我正在按要求添加 Book 结构
struct Book: Hashable, Codable, Identifiable {
var id: UUID
var name: String
var author: String
var page: String
var total: String
var image: String
}
编辑 2:这是针对 iOS 应用
编辑 3:我的加载数据功能
func load<T: Decodable>(_ filename: String) -> T {
let data: Data
guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
fatalError("Couldn't find \(filename) in main bundle.")
}
do {
data = try Data(contentsOf: file)
} catch {
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}
do {
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
} catch {
fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}
您可能没有覆盖磁盘上的现有文件。在将数据写入磁盘时尝试 options: .atomic
。
func writeJSON(_ bookData: [Book]) {
do {
let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("list.json")
try JSONEncoder().encode(bookData).write(to: fileURL, options: .atomic)
} catch {
print(error)
}
}
edit/update:
这里的问题是您没有将文件保存在您认为应该保存的位置。 Bundle目录为read-only,与你的App文档目录无关
func load<T: Decodable>(_ filename: String) -> T? {
// no problem to force unwrap here you actually do want it to crash if the file it is not inside your bundle
let readURL = Bundle.main.url(forResource: filename, withExtension: "json")!
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let jsonURL = documentDirectory
.appendingPathComponent(filename)
.appendingPathExtension("json")
// check if the file has been already copied from the Bundle to the documents directory
if !FileManager.default.fileExists(atPath: jsonURL.path) {
// if not copy it to the documents (not it is not a read-only anymore)
try? FileManager.default.copyItem(at: readURL, to: jsonURL)
}
// read your json from the documents directory to make sure you get the latest version
return try? JSONDecoder().decode(T.self, from: Data(contentsOf: jsonURL))
}
func writeJSON(_ bookData: [Book]) {
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let jsonURL = documentDirectory
.appendingPathComponent("list")
.appendingPathExtension("json")
// write your json at the documents directory and use atomic option to override any existing file
try? JSONEncoder().encode(bookData).write(to: jsonURL, options: .atomic)
}