简体   繁体   中英

SwiftUI - View doesn't update despite using @Published and @ObservedObject

I've had issues updating the Home View of my app using SwiftUI.

So, I have a Dog struct ( Dog.swift ) :

struct Dog: Identifiable {

var id = UUID()
var name: String
var race: String
var age: Int
var gender: String
var sterile: Bool
var pictureURL: String
var location: String
var dogFriendly: Bool
var catFriendly: Bool
var childFriendly: Bool
var needsGarden: Bool
var isClean: Bool
}

My goal is to press this Button inside AddView.swift :

@ObservedObject var viewModel = AddViewModel()
 ************** LONG UI CODE *******************
.navigationBarItems(trailing:
                    Button("Publish") {
                        viewModel.dogs.append(Dog(name: self.name, race: races[selectedRace], age: self.age, gender: genders[selectedGender], sterile: self.isSterile, pictureURL: "", location: "", dogFriendly: self.isDogFriendly, catFriendly: self.isCatFriendly, childFriendly: self.isChildFriendly, needsGarden: self.needsGarden, isClean: self.isClean))
                        print(viewModel.dogs)
                })

to append dogs to the Dog array inside AddViewModel.swift :

class AddViewModel: ObservableObject {

@Published var dogs: [Dog] = []
}

and then show the information in a CardView:

struct CardView: View {

//MARK: - Properties

@State var dog: Dog

//MARK: - View

var body: some View {
******* LONG UI CODE ********
}

and display those CardView in my HomeView:

struct HomeView: View {

@ObservedObject var viewModel = AddViewModel()


var body: some View {
    ScrollView {
        VStack {
            ForEach(viewModel.dogs) { dog in
                CardView(dog: dog) // this doesn't work
                Text(dog.name) // this doesn't work neither
            }
        }
    }
}

}

Can someone help me about it and give me an advice on how to proceed?

Thank you for your generous help!

Change @State to @Bindig will fix it.

CardView:

struct CardView: View {

//MARK: - Properties

@Binding var dog: Dog

//MARK: - View

var body: some View {
******* LONG UI CODE ********
}

I think you want to append Array of Dog inside AddView and show the updated data inside HomeView . So, you just declared an instance of AddViewModel inside each view separately. The both instances inside views don't not observe each other. To get around this, I prefer to use Singleton pattern. Here is my sample code.

struct ContentView: View {
    @ObservedObject private var viewModel: AddViewModel = .sharedInstance
    @State private var showSheet = false
    var body: some View {
        NavigationView {
            ScrollView {
                ForEach(viewModel.dogs) { dog in
                    Text(dog.name)
                        .frame(height: 25)
                }
            }
            .navigationTitle("DogZ")
            .navigationBarItems(leading: Button(action: {
                showSheet.toggle()
            }, label: {
                Text("Show")
            }))
        }
        .sheet(isPresented: $showSheet, content: {
            AddView()
        })
    }
}

struct AddView: View {
    @ObservedObject private var viewModel: AddViewModel = .sharedInstance
    @Environment(\.presentationMode) var presentationMode
    var body: some View {
        NavigationView {
            Text("Sheet Add View")
                .navigationBarItems(trailing: Button(action: {
                    viewModel.dogs.append(Dog(name: "Blacky"))
                    presentationMode.wrappedValue.dismiss()
                }, label: {
                    Text("Add")
                }))
        }
    }
}


class AddViewModel: ObservableObject {
    @Published var dogs = [Dog]()
    static var sharedInstance = AddViewModel()
}

struct Dog: Identifiable {
    var id = UUID()
    var name: String
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM