0
votes

Okay so I've been working on this for several days now and have not had any luck with an answer that makes any sense. I have a form in SwiftUI, using @ObservedObject to pull variables from a struct. In that form, I have a variety of text fields and pickers that the user can interact with. HOWEVER, I cannot figure out how to get my "Add" button to actually add that data to any of the other views in the app. I followed the sandwiches tutorial from WWDC20, with significant changes, so there is a swift file with "testData" and essentially I'm trying to get it so that the button uses the user input to append the testData and show that instead of nothing.

struct Horse: Identifiable {
    var id = UUID()
    var name: String
    var gender: String
    var breed: String
    var type: String
    var scale: String
    var brand: String
    var finish: String
    var specialty: String
    
    
    var imageName: String { return name }
    var thumbnailName: String { return name + "Thumb" }
}

let testData = [
    Horse(name: "Van Gogh", gender: "Stallion", breed: "Unknown", type: "Customized", scale: "Stablemate", brand: "Peter Stone", finish: "Gloss", specialty: "OOAK")
]

So this is what I'm using to establish testData and the parameters for what should be included in it.

func addANewHorse() {
    withAnimation {
        testStore.horses.append(Horse(name: "\(horseDetails.horseName)", gender: "\(horseDetails.selectedGender.rawValue)", breed: "\(horseDetails.horseBreed)", type: "\(horseDetails.type.rawValue)", scale: "\(horseDetails.scale.rawValue)", brand: "\(horseDetails.brand.rawValue)", finish: "\(horseDetails.finish.rawValue)", specialty: "\(horseDetails.specialty.rawValue)"))
    }
}

Button("Add", action: {
    addANewHorse();
    self.presentationMode.wrappedValue.dismiss()
})

And that is what I'm using to try and append the testData to update with the users input. I know this is kind of choppy but does anyone have any advice whatsoever? ---EDIT--- My main app file looks like this...

@main

struct Pferd_HerdApp: App {

@StateObject private var store = HorseStore()
@StateObject private var horseDetails = HorseDetails()

var body: some Scene {
    WindowGroup {
        ContentView(store: store, horseDetails: HorseDetails())
    }
}

}

my horse store class looks like this...

class HorseStore: ObservableObject {
@Published var horses: [Horse]

init(horses: [Horse] = []) {
    self.horses = horses
}

}

let testStore = HorseStore(horses: testData)

Also, "HorseDetails" is the observableobject I'm trying to pull data from to append the testData, so here is the code for that

class HorseDetails: ObservableObject {
@Published var horseName = ""
@Published var selectedGender = Gender.allCases[0]
@Published var horseBreed = ""
@Published var purchaseDate = Date()
@Published var winCount = ""
@Published var notes = ""
@Published var brand = Brands.allCases[0]
@Published var type = Type.allCases[0]
@Published var scale = Scale.allCases[0]
@Published var finish = Finish.allCases[0]
@Published var specialRun = false
@Published var specialty = Specialty.allCases[0]

} var horseDetails = HorseDetails()

and I changed the let for testData to a variable

1
let variable define constant, it initialise for first time only, So define your list as @State var list[Horse] = [] - Amir

1 Answers

0
votes

Since your Question leaves a lot of code out, I will be making a few assumptions. I'm assuming that your form (where you have the button to add data) and your view for displaying the data are in two different views. You have not included your view model in the code, although there was an instance of your view model (testStore) used in the code above. You need to make sure that somewhere at the root of your view hierarchy, you made an instance of your view model (I'm assuming its called TestStoreViewModel) and passed that as an environment object to your subviews. For example, you should something like this

@main
struct YourApp: App {
    let testStoreViewModel = TestStoreViewModel()
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(testStoreViewModel)
        }
    }
}

in all of your views where you need to use the data from your TestStoreViewModel, you should declare it like so

@EnvironmentObject var testStore:TestStoreViewModel

Using environment objects means that your observable object is automatically synced across all of your views that use the environment object. Everything else in the code above should work fine with the use of EnvironmentObjects and a single source of truth. For more on environment objects, you can check out this article which in my opinion is great at explaining Environment Objects in swiftui. It is also important to note that in that article, it mentioned the use of a SceneDelegte and the ContentView being wrapped around a UIHostingController. That was replaced by the first block of code I showed you above.