Hello,
I'm training on document based app, and I can't understand why my file is not editable. Every time I add a letter to a text field, it is deleted immediatly.
I know this is a very important skill to get, but I'm completely stuck.
Thank you very much
ContentView
import SwiftUI
struct ContentView: View {
@Binding var document: FamilyDocument
var body: some View {
FamilyView(family: $document.family)
}
}
DocumentAppMacApp
import SwiftUI
@main
struct DocumentApp: App {
var body: some Scene {
DocumentGroup(newDocument: FamilyDocument()) { file in
ContentView(document: file.$document)
}
}
}
FamilyDocument
import SwiftUI
import UniformTypeIdentifiers
struct FamilyDocument: FileDocument {
// tell the system we support only plain text
static var readableContentTypes = [UTType.plainText]
// by default our document is empty
@State var family: Family
// a simple initializer that creates new, empty documents
init() {
print("Init family file")
family = Family(animals: [
Animal(name: "Thémis", species: "Chien", age: 1),
Animal(name: "Fidji", species: "Chat", age: 13),
])
print(family.animals.count)
}
// this initializer loads data that has been saved previously
init(configuration: ReadConfiguration) throws {
if let data = configuration.file.regularFileContents {
let decoder = JSONDecoder()
let decodedData = try! decoder.decode(Family.self, from: data)
family = decodedData
print("Data read")
} else {
throw CocoaError(.fileReadCorruptFile)
}
}
// this will be called when the system wants to write our data to disk
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
let encoder = JSONEncoder()
guard let data = try? encoder.encode(family) else {
print("File not readable")
throw CancellationError()
}
print("To be saved.")
return FileWrapper(regularFileWithContents: data)
}
}
FamilyView
import SwiftUI
struct FamilyView: View {
@Binding var family: Family
var body: some View {
NavigationStack {
Text("Here is my family")
Text(family.name)
Text("There are \(family.animals.count) animals.")
ForEach($family.animals) { $animal in
AnimalView(animal: $animal)
}
}
.toolbar {
Button("Add") {
family.addAnimal()
}
Button("Clear") {
family.clear()
}
}
.navigationTitle("Family")
}
}
struct FamilyView_Previews: PreviewProvider {
static var previews: some View {
let animals = [
Animal(name: "Thémis", species: "Chien", age: 1)
]
let family = Family(animals: animals)
FamilyView(family: .constant(family))
}
}
Family
import SwiftUI
struct Family: Codable {
enum CodingKeys: CodingKey {
case animals
case name
}
@State var animals: [Animal]
@State var name: String = "Default name"
init() {
self.animals = []
}
init(animals: [Animal]) {
self.animals = animals
self.name = "Init name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
animals = try container.decode([Animal].self, forKey: .animals)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(animals, forKey: .animals)
}
func clear() {
animals = []
print("Clear!")
}
func addAnimal() {
animals.append(Animal())
print("New animal append!")
}
}
AnimalView
import SwiftUI
struct AnimalView: View {
@Binding var animal: Animal
var body: some View {
List {
HStack {
Text("Name")
Spacer()
TextField("name", text: $animal.name)
}
HStack {
Text("Species")
Spacer()
TextField("species", text: $animal.species)
}
HStack {
Text("Age")
Spacer()
TextField("age", value: $animal.age, formatter: NumberFormatter())
}
}
}
}
struct AnimalView_Previews: PreviewProvider {
static var previews: some View {
let animal = Animal(name: "Thémis", species: "Chien", age: 1)
AnimalView(animal: .constant(animal))
}
}
Animal
import SwiftUI
struct Animal: Codable, Identifiable {
var id = UUID()
var name: String = ""
var species: String = ""
var age: Int = 0
}