Загружайте разные данные по идентификатору в одном и том же представлении

#swift #swiftui #swiftui-navigationlink #observableobject

#swift #свифтуи #swiftui-navigationlink #observableobject

Вопрос:

Я хочу загрузить разные данные в одно и то же представление, используя ObservableObject с индексом.

Как вы можете видеть в простом демонстрационном примере, прилагаемом, когда я просматриваю представления, меняя идентификатор, чтобы загрузить разные данные, это работает.

Но когда в какой-либо момент я изменяю другие данные из другого наблюдаемого объекта (в данном случае AnotherObservable), тогда мое представление прерывается, и любые данные вообще не найдены.

Навигация работает…

Работает

Как только я нажму кнопку Изменить заголовок…

Проблема

Чтобы проверить проблему, просто скопируйте и вставьте код и перейдите по данным с помощью <- ->, а затем нажмите кнопку Изменить заголовок

 class DemoItemsLoader: ObservableObject {
    @Published var items = [1, 2, 3, 4]
}

class DemoArticleLoader: ObservableObject {
    @Published var items = [1 : "One", 2 : "Two" , 3 : "Three", 4 : "Four"]
    @Published var realData: String?

    func loadItemForID(id: Int) {
        realData = items[id] ?? "Not found"
    }
}
class AnotherObservable: ObservableObject {
    @Published var title: String = "Title"
}


struct Class1: View {
    @StateObject var anotherObservable = AnotherObservable()
    @StateObject var itemsLoader = DemoItemsLoader()
    var body: some View {
        NavigationView{
            VStack {
                ForEach(itemsLoader.items, id: .self) { item in
                    NavigationLink(
                        destination: Class2(anotherObservable: anotherObservable, articleLoader: DemoArticleLoader(), id: item)) {
                        Text("(item)")
                    }
                }
            }
        }
    }
}

struct Class2: View {
    @ObservedObject var anotherObservable: AnotherObservable
    @ObservedObject var articleLoader: DemoArticleLoader
    @State var id: Int

    var body: some View {
        VStack {
            Text(anotherObservable.title)
            Text(articleLoader.realData ?? "Not found")
            HStack {
                Spacer()
                Button(action: {
                    if id > 1 {
                        id = id - 1
                        articleLoader.loadItemForID(id: id)
                    }
                }) {
                    Text("<-")
                }
                Button(action: {
                    if id < articleLoader.items.count {
                        id = id   1
                        articleLoader.loadItemForID(id: id)
                    }

                }) {
                    Text("->")
                }
                Button(action: {
                    anotherObservable.title = "Another Title"
                }) {
                    Text("Change title")
                }
                Spacer()
            }
        }
        .onAppear { articleLoader.loadItemForID(id: id)}
    }
}
 

Ответ №1:

Проблема в том, что вы звоните loadItemForID onAppear только:

 .onAppear { articleLoader.loadItemForID(id: id)}
 

И когда вы меняете заголовок, вышеупомянутая функция больше не вызывается.

Вероятно, самым простым решением является сохранение DemoArticleLoader() как a @StateObject , чтобы оно не воссоздавалось каждый раз:

 struct Class1: View {
    @StateObject var anotherObservable = AnotherObservable()
    @StateObject var itemsLoader = DemoItemsLoader()
    @StateObject var articleLoader = DemoArticleLoader() // create once

    var body: some View {
        NavigationView {
            VStack {
                ForEach(itemsLoader.items, id: .self) { item in
                    NavigationLink(
                        // pass here
                        destination: Class2(anotherObservable: anotherObservable, articleLoader: articleLoader, id: item)) {
                        Text("(item)")
                    }
                }
            }
        }
    }
}