Просмотр не обновляется при нажатии с помощью навигационной ссылки

Я столкнулся с проблемой, когда представление не обновляется автоматически с помощью объекта @Observable.

struct Person: Identifiable {
  var id: Int
  var name: String

  init(id: Int, name: String){
      self.id = id
      self.name = name
  }

}

class People: ObservableObject {
  @Published var people: [Person]
  @Published var kitchens: [Kitchen]

  init(){
      self.people = [
          Person(id: 1, name:"Javier"),
          Person(id: 2, name:"Juan"),
          Person(id: 3, name:"Pedro")]
 }
}

struct ContentView: View {
@ObservedObject var mypeople: People

var body: some View {
    VStack{
        ForEach(mypeople.people){ person in
            Text("\(person.name)")
        }
        Button(action: {
            self.mypeople.people.append(Person(id: 7, name: "New person"))
        }) {
            Text("Add/Change name")
        }
    }.onAppear {
        self.mypeople.people.append(Person(id: 7, name: "New person"))
    }
}
}

Итак, что я хочу сделать, так это добавить нового человека в onAppear вместо добавления нового человека нажатием кнопки. Короче говоря, в массиве people уже есть три человека, и мне нужно добавить четвертого сразу после перехода на это представление.

Странно то, что человек добавляется, если это представление, если это корневое представление, однако оно не работает, когда это представление отправляется с помощью навигационной ссылки. Во втором случае новый человек добавляется и удаляется сразу, сохраняя количество людей в массиве до трех.

Однако нового человека легко добавить одним нажатием кнопки. Я застрял здесь на несколько часов. Любая помощь будет более чем оценена! Заранее спасибо!

ИЗМЕНИТЬ

Я немного отлаживал, чтобы выяснить проблему. Итак, новый человек автоматически добавляется в onAppear в следующих сценариях:

1) Если ContentView является корневым представлением приложения. 2) Если ContentView выталкивается из самого первого представления в иерархии родительского представления. Означает, что есть подвиды ContentView. Ссылка навигации из вложенных представлений создает эту проблему, однако ссылка навигации непосредственно из ContentView успешно добавляет человека.

А для создания навигационной ссылки я использовал:

NavigationLink(destination:  ContentView()) {
     Text("View All")
}

person Amrit Sidhu    schedule 15.04.2020    source источник
comment
Не могли бы вы показать код, как вы им управляете в случае NavigationLink?   -  person Asperi    schedule 15.04.2020
comment
На самом деле проблема в самой ссылке навигации. Я добавляю еще какое-то описание.   -  person Amrit Sidhu    schedule 15.04.2020
comment
@Asperi: я отредактировал сообщение   -  person Amrit Sidhu    schedule 15.04.2020
comment
Я не могу воспроизвести вашу проблему. Обновите свой код, включив в него все необходимое, чтобы увидеть проблему в действии. Например, вы никогда не показываете нам, где создается объект People (). Кажется, проблема в том, что объект People перезаписывается, но поскольку мы не видим эту часть вашего кода, я не могу сказать наверняка.   -  person kontiki    schedule 16.04.2020


Ответы (2)


относится ли это к сценарию, который вы упомянули в своем комментарии:

struct TheNavView: View {
@ObservedObject var mypeople: People
@State var newId = Int(arc4random())
var body: some View {
    // the view that create "New person" onAppear
    VStack{
        ForEach(mypeople.people){ person in
            Text("\(person.name)")
        }
        Button(action: {
            self.mypeople.people.append(Person(id: self.newId, name: "New person"))
        }) {
            Text("Add/Change name")
        }
    }.onAppear {
        print("--------> onAppear self.newId: \(self.newId)")
        self.mypeople.people.append(Person(id: self.newId, name: "New person"))
    }
}
}

struct TheSubView: View {
@ObservedObject var mypeople: People
var body: some View {
    // the subView that pushes using NavigationLink
    NavigationView {
        NavigationLink(destination: TheNavView(mypeople: mypeople)) {
            Text("View All")
        }
    }.navigationViewStyle(StackNavigationViewStyle())
}
}

struct ContentView: View {
@ObservedObject var mypeople: People
var body: some View {
    // the ContentView with a subView
    TheSubView(mypeople: mypeople)
}
}
person workingdog    schedule 16.04.2020
comment
Да, это прекрасно работает. Однако в моем случае есть какая-то проблема, которая не позволяет обновлению представления. - person Amrit Sidhu; 22.04.2020
comment
В моем случае я не могу передать наблюдаемый класс в целевое представление. У моего целевого представления есть свой собственный наблюдаемый класс. В этом сценарии, если целевое представление является корневым, оно работает отлично, однако, если целевое представление выталкивается из вложенного представления, оно не обновляется. - person Amrit Sidhu; 22.04.2020

хорошо, если я правильно понимаю, вы хотите добавить нового человека в onAppear вместо добавления нового человека нажатием кнопки. Но человек добавляется, если это представление является корневым, однако оно не работает, когда это представление передается с помощью навигационной ссылки.

Итак, я приготовил тест, который работает:

struct Person: Identifiable {
var id: Int
var name: String
init(id: Int, name: String){
    self.id = id
    self.name = name
}
}

struct Kitchen: Identifiable {
var id: Int
var name: String
init(id: Int, name: String){
    self.id = id
    self.name = name
}
}

class People: ObservableObject {
@Published var people: [Person]
@Published var kitchens: [Kitchen]
init() {
    self.people = [ Person(id: 1, name:"Javier"),Person(id: 2, name:"Juan"),Person(id: 3, name:"Pedro")]
    self.kitchens = [ Kitchen(id: 1, name:"Kitchen1"),Kitchen(id: 2, name:"Kitchen2"), Kitchen(id: 3, name:"Kitchen3")]
}
}

struct SecondView: View {
@ObservedObject var mypeople: People
@State var newId = Int(arc4random())
var body: some View {
    VStack{
        ForEach(mypeople.people){ person in
            Text("\(person.name)")
        }
        Button(action: {
            self.mypeople.people.append(Person(id: self.newId, name: "New person"))
        }) {
            Text("Add/Change name")
        }
    }.onAppear {
        print("--------> onAppear")
        self.mypeople.people.append(Person(id: self.newId, name: "New person"))
    }
}
}

struct ContentView: View {
@ObservedObject var mypeople: People
var body: some View {
    NavigationView {
        NavigationLink(destination: SecondView(mypeople: mypeople)) {
            Text("View All")
        }
    }.navigationViewStyle(StackNavigationViewStyle())
}
}

конечно, в SceneDelegate вы должны объявить:

var people = People()
window.rootViewController = UIHostingController(rootView: ContentView(mypeople: people))
person workingdog    schedule 16.04.2020
comment
Подход, который вы упомянули ed, будет работать без каких-либо проблем. Проблема возникает, когда ContentView имеет внутри некоторый subView, который проталкивает ссылку навигации из самого subView, а не из Content View. - person Amrit Sidhu; 16.04.2020