如何附加到结构数组并保持更改持久?
How to Append to Array of Structs and have Change Persistant?
我希望能够将对象列表存储在单独的 Swift 文件中,并在页面中调用它们以显示它们。我用这段代码成功做到了这一点:
import Foundation
import SwiftUI
struct MatchInfo: Hashable, Codable {
let theType: String
let theWinner: String
let theTime: String
let id = UUID()
}
var matchInfo = [
MatchInfo(theType: "Capitalism", theWinner: "Julia", theTime: "3/3/2021"),
MatchInfo(theType: "Socialism", theWinner: "Julia", theTime: "3/2/2021"),
MatchInfo(theType: "Authoritarianism", theWinner: "Luke", theTime: "3/1/2021")
]
在此处的另一页上播放比赛后我追加到列表的位置:
matchInfo.insert(MatchInfo(theType: typeSelection, theWinner: winnerName, theTime: "\(datetimeWithoutYear)" + "\(year)"), at: 0)
下面是我将其调用到列表中的另一页上的一些代码:
List {
ForEach(matchInfo, id: \.self) { matchData in
matchRow(matchData : matchData)
} .background(Color("invisble"))
.listRowBackground(Color("invisble"))
} .frame(height: 490)
...
struct matchRow: View {
let matchData: MatchInfo
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(matchData.theType)
.font(.system(size: 20, weight: .medium, design: .default))
Text(" Winner: " + matchData.theWinner)
}
Spacer()
Text(matchData.theTime)
.padding(.leading, 40)
.multilineTextAlignment(.trailing)
}
.foregroundColor(.white)
.accentColor(.white)
}
}
但是此代码不会通过应用程序重新启动来保存。我以前从来没有通过重启保存过任何东西,并且一直在努力寻找一个足够简单让我理解的答案。如何在下次打开应用程序时更新列表而不让其消失?
好的,下面是一个关于如何保存到文档文件夹/从文档文件夹加载的示例。
首先确保您反对 MatchInfo 符合此协议。
import Foundation
protocol LocalFileStorable: Codable {
static var fileName: String { get }
}
extension LocalFileStorable {
static var localStorageURL: URL {
guard let documentDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first else {
fatalError("Can NOT access file in Documents.")
}
return documentDirectory
.appendingPathComponent(self.fileName)
.appendingPathExtension("json")
}
}
extension LocalFileStorable {
static func loadFromFile() -> [Self] {
do {
let fileWrapper = try FileWrapper(url: Self.localStorageURL, options: .immediate)
guard let data = fileWrapper.regularFileContents else {
throw NSError()
}
return try JSONDecoder().decode([Self].self, from: data)
} catch _ {
print("Could not load \(Self.self) the model uses an empty collection (NO DATA).")
return []
}
}
}
extension LocalFileStorable {
static func saveToFile(_ collection: [Self]) {
do {
let data = try JSONEncoder().encode(collection)
let jsonFileWrapper = FileWrapper(regularFileWithContents: data)
try jsonFileWrapper.write(to: self.localStorageURL, options: .atomic, originalContentsURL: nil)
} catch _ {
print("Could not save \(Self.self)s to file named: \(self.localStorageURL.description)")
}
}
}
extension Array where Element: LocalFileStorable {
///Saves an array of LocalFileStorables to a file in Documents
func saveToFile() {
Element.saveToFile(self)
}
}
您的主要内容视图应如下所示:(我修改了您的对象以使其更简单。)
import SwiftUI
struct MatchInfo: Hashable, Codable, LocalFileStorable {
static var fileName: String {
return "MatchInfo"
}
let description: String
}
struct ContentView: View {
@State var matchInfos = [MatchInfo]()
var body: some View {
VStack {
Button("Add Match Info:") {
matchInfos.append(MatchInfo(description: "Nr." + matchInfos.count.description))
MatchInfo.saveToFile(matchInfos)
}
List(matchInfos, id: \.self) {
Text([=11=].description)
}
.onAppear(perform: {
matchInfos = MatchInfo.loadFromFile()
})
}
}
}
我希望能够将对象列表存储在单独的 Swift 文件中,并在页面中调用它们以显示它们。我用这段代码成功做到了这一点:
import Foundation
import SwiftUI
struct MatchInfo: Hashable, Codable {
let theType: String
let theWinner: String
let theTime: String
let id = UUID()
}
var matchInfo = [
MatchInfo(theType: "Capitalism", theWinner: "Julia", theTime: "3/3/2021"),
MatchInfo(theType: "Socialism", theWinner: "Julia", theTime: "3/2/2021"),
MatchInfo(theType: "Authoritarianism", theWinner: "Luke", theTime: "3/1/2021")
]
在此处的另一页上播放比赛后我追加到列表的位置:
matchInfo.insert(MatchInfo(theType: typeSelection, theWinner: winnerName, theTime: "\(datetimeWithoutYear)" + "\(year)"), at: 0)
下面是我将其调用到列表中的另一页上的一些代码:
List {
ForEach(matchInfo, id: \.self) { matchData in
matchRow(matchData : matchData)
} .background(Color("invisble"))
.listRowBackground(Color("invisble"))
} .frame(height: 490)
...
struct matchRow: View {
let matchData: MatchInfo
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(matchData.theType)
.font(.system(size: 20, weight: .medium, design: .default))
Text(" Winner: " + matchData.theWinner)
}
Spacer()
Text(matchData.theTime)
.padding(.leading, 40)
.multilineTextAlignment(.trailing)
}
.foregroundColor(.white)
.accentColor(.white)
}
}
但是此代码不会通过应用程序重新启动来保存。我以前从来没有通过重启保存过任何东西,并且一直在努力寻找一个足够简单让我理解的答案。如何在下次打开应用程序时更新列表而不让其消失?
好的,下面是一个关于如何保存到文档文件夹/从文档文件夹加载的示例。
首先确保您反对 MatchInfo 符合此协议。
import Foundation
protocol LocalFileStorable: Codable {
static var fileName: String { get }
}
extension LocalFileStorable {
static var localStorageURL: URL {
guard let documentDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first else {
fatalError("Can NOT access file in Documents.")
}
return documentDirectory
.appendingPathComponent(self.fileName)
.appendingPathExtension("json")
}
}
extension LocalFileStorable {
static func loadFromFile() -> [Self] {
do {
let fileWrapper = try FileWrapper(url: Self.localStorageURL, options: .immediate)
guard let data = fileWrapper.regularFileContents else {
throw NSError()
}
return try JSONDecoder().decode([Self].self, from: data)
} catch _ {
print("Could not load \(Self.self) the model uses an empty collection (NO DATA).")
return []
}
}
}
extension LocalFileStorable {
static func saveToFile(_ collection: [Self]) {
do {
let data = try JSONEncoder().encode(collection)
let jsonFileWrapper = FileWrapper(regularFileWithContents: data)
try jsonFileWrapper.write(to: self.localStorageURL, options: .atomic, originalContentsURL: nil)
} catch _ {
print("Could not save \(Self.self)s to file named: \(self.localStorageURL.description)")
}
}
}
extension Array where Element: LocalFileStorable {
///Saves an array of LocalFileStorables to a file in Documents
func saveToFile() {
Element.saveToFile(self)
}
}
您的主要内容视图应如下所示:(我修改了您的对象以使其更简单。)
import SwiftUI
struct MatchInfo: Hashable, Codable, LocalFileStorable {
static var fileName: String {
return "MatchInfo"
}
let description: String
}
struct ContentView: View {
@State var matchInfos = [MatchInfo]()
var body: some View {
VStack {
Button("Add Match Info:") {
matchInfos.append(MatchInfo(description: "Nr." + matchInfos.count.description))
MatchInfo.saveToFile(matchInfos)
}
List(matchInfos, id: \.self) {
Text([=11=].description)
}
.onAppear(perform: {
matchInfos = MatchInfo.loadFromFile()
})
}
}
}