ios - 在 iOS、SwiftUI 的 Documents Directory 中保存数据
问题描述
我无法弄清楚如何使用 SwiftUI 在文档目录中保存数据(多个属性)。我知道两种变体,第一种 - 当你有一个数组属性并且效果很好时,这里的问题 - 我不知道如何向它添加其他属性。或者,为一个项目的每个属性创建大约 3 个这样的 swift-files 是正常的。
1 个变体,保存在文档目录中:
class Stack: ObservableObject {
@Published var cards: [Card]
static let saveKey = "SavedCards"
init() {
self.cards = []
if let data = loadFile() {
if let decoded = try? JSONDecoder().decode([Card].self, from: data) {
self.cards = decoded
return
}
}
}
func add(card: Card) {
cards.insert(card, at: 0)
save()
}
func save() {
if let encoded = try? JSONEncoder().encode(cards) {
saveFile(data: encoded)
}
}
private func saveFile(data: Data) {
let url = getDocumentsDirectory().appendingPathComponent(Self.saveKey)
do {
try data.write(to: url, options: [.atomicWrite, .completeFileProtection])
} catch let error {
print("Could not write data: " + error.localizedDescription)
}
}
func loadFile() -> Data? {
let url = getDocumentsDirectory().appendingPathComponent(Self.saveKey)
if let data = try? Data(contentsOf: url) {
return data
}
return nil
}
private func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
}
第二种变体是对每个属性使用 CodingKeys。但我无法弄清楚如何在此处添加方法并在其他视图中使用它,例如通过按下按钮来保存数据。对于每次数据更改,我似乎必须一遍又一遍地在每个视图中进行编码和解码。这似乎是错误的。
2 个带编码键的变体
class Profile: Codable, ObservableObject {
enum CodingKeys: CodingKey {
case categories, playedCards, playedRounds
}
@Published var categories: [Category] = [Category.red, .green, .blue, .yellow, .pink, .gray]
@Published var playedCards = 0
@Published var playedRounds = 0
init() { }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
categories = try container.decode([Category].self, forKey: .categories)
playedCards = try container.decode(Int.self, forKey: .playedCards)
playedRounds = try container.decode(Int.self, forKey: .playedRounds)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(categories, forKey: .categories)
try container.encode(playedCards, forKey: .playedCards)
try container.encode(playedRounds, forKey: .playedRounds)
}
}
所以我的问题是如何使用具有多个变量的 1 个变体。或者,如果我应该使用第二个变体,我怎样才能“很好地”编码和解码来自其他视图的变量。
解决方案
目前,我对第二个变体的解决方案是在 ContentView 中编写标准的 decode() / encode() 方法,并在工作表视图的onDismiss:中使用它来保存来自不同屏幕的数据而不重复。
func loadData() {
let filename = getDocumentsDiretory().appendingPathComponent("SavedData")
do {
let data = try Data(contentsOf: filename)
profile = try JSONDecoder().decode(Profile.self, from: data)
} catch {
print("Unable to load saved profile data")
}
}
func saveData() {
do {
let filename = getDocumentsDiretory().appendingPathComponent("SavedData")
let data = try JSONEncoder().encode(self.profile)
try data.write(to: filename, options: [.atomic, .completeFileProtection])
} catch {
print("Unable to save profile data")
}
}
func getDocumentsDiretory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
.sheet(isPresented: $showingSheet, onDismiss: saveData) {
ProfileView()
}
.onAppear(perform: loadData)
推荐阅读
- python - 使用 discord.py 循环访问公会成员
- git - 将 VCS 添加到复杂的开发/生产环境的最佳 git 策略
- parsing - AllenNLP:使用 Taskdemo 和 Python 库的不同选区解析
- python - 如何定位 Pyspark Dataframe 中特定行中的特定列?
- batch-file - 删除文件计数器有效,但提供随机数
- python - 想在 Python 中使用正则表达式对单词进行分组,就像字符类和重复量词对字符进行分组一样
- java - 如何提高简单 java 游戏循环中的帧率?
- sql-server - SQL Server dm_exec_input_buffer linq 动态查询的问题
- angular - 数据表搜索不能很好地过滤
- linux - 无法在 ubuntu 中运行 Apache2 服务器