Как сбросить переменную состояния дочернего представления с SwiftUI? - PullRequest
0 голосов
/ 09 апреля 2020

Я уверен, что это что-то очень глупое, но как можно сбросить значение состояния дочернего представления, когда другое состояние изменилось?

Например, код ниже показывает 2 папки, которые соответственно имеют 2 и 3 элемента., Которые можно редактировать.

Если выбрать вторую папку (Работа) и ее 3-й элемент (Питер), а затем выбрать первую папку (Главная), приложение вылетает, так как selectedItemIndex отсутствует границ.

Я пытался «сбросить» значение состояния, когда представление инициализируется, но похоже, что изменение состояния приводит к появлению «runtime: SwiftUI: изменение состояния во время обновления представления, это приведет к неопределенному поведение." предупреждение.

init(items: Binding<[Item]>) {  
    self._items = items  
    self._selectedItemIndex = State(wrappedValue: 0)  
}  

Как правильно сделать это? Спасибо!

Вот код:

AppDelegate.swift


    import Cocoa
    import SwiftUI

    @NSApplicationMain
    class AppDelegate: NSObject, NSApplicationDelegate {

        var window: NSWindow!


        func applicationDidFinishLaunching(_ aNotification: Notification) {
            // Create the SwiftUI view that provides the window contents.
            let store = ItemStore()
            let contentView = ContentView(store: store)

            // Create the window and set the content view. 
            window = NSWindow(
                contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
                styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
                backing: .buffered, defer: false)
            window.center()
            window.setFrameAutosaveName("Main Window")
            window.contentView = NSHostingView(rootView: contentView)
            window.makeKeyAndOrderFront(nil)
        }

        func applicationWillTerminate(_ aNotification: Notification) {
            // Insert code here to tear down your application
        }
    }

ContentView.swift


    import SwiftUI

    final class ItemStore: ObservableObject {
        @Published var data: [Folder] = [Folder(name: "Home",
                                                items: [Item(name: "Mark"), Item(name: "Vincent")]),
                                         Folder(name: "Work",
                                                items:[Item(name: "Joseph"), Item(name: "Phil"), Item(name: "Peter")])]
    }

    struct Folder: Identifiable {
        var id = UUID()
        var name: String
        var items: [Item]
    }

    struct Item: Identifiable {
        static func == (lhs: Item, rhs: Item) -> Bool {
            return true
        }

        var id = UUID()
        var name: String
        var content = Date().description

        init(name: String) {
            self.name = name
        }
    }

    struct ContentView: View {
        @ObservedObject var store: ItemStore

        @State var selectedFolderIndex: Int?

        var body: some View {
            HSplitView {
                // FOLDERS
                List(selection: $selectedFolderIndex) {
                    Section(header: Text("Groups")) {
                        ForEach(store.data.indexed(), id: \.1.id) { index, folder in
                            Text(folder.name).tag(index)
                        }
                    }.collapsible(false)
                }
                .listStyle(SidebarListStyle())

                // ITEMS
                if selectedFolderIndex != nil {
                    ItemsView(items: $store.data[selectedFolderIndex!].items)
                }
            }
            .frame(minWidth: 800, maxWidth: .infinity, maxHeight: .infinity)
        }
    }


    struct ItemsView: View {
        @Binding var items: [Item]
        @State var selectedItemIndex: Int?

        var body: some View {
            HSplitView {
                List(selection: $selectedItemIndex) {
                    ForEach(items.indexed(), id: \.1.id) { index, item in
                        Text(item.name).tag(index)
                    }
                }
                .frame(width: 300)

                if selectedItemIndex != nil {
                    DetailView(item: $items[selectedItemIndex!])
                    .padding()
                    .frame(minWidth: 200, maxHeight: .infinity)
                }
            }
        }

        init(items: Binding) {
            self._items = items
            self._selectedItemIndex = State(wrappedValue: 0)
        }
    }


    struct DetailView: View {
        @Binding var item: Item

        var body: some View {
            VStack {
                TextField("", text: $item.name)
            }
        }
    }

    // Credit: https://swiftwithmajid.com/2019/07/03/managing-data-flow-in-swiftui/

    struct IndexedCollection: RandomAccessCollection {
        typealias Index = Base.Index
        typealias Element = (index: Index, element: Base.Element)

        let base: Base

        var startIndex: Index { base.startIndex }

        var endIndex: Index { base.endIndex }

        func index(after i: Index) -> Index {
            base.index(after: i)
        }

        func index(before i: Index) -> Index {
            base.index(before: i)
        }

        func index(_ i: Index, offsetBy distance: Int) -> Index {
            base.index(i, offsetBy: distance)
        }

        subscript(position: Index) -> Element {
            (index: position, element: base[position])
        }
    }

    extension RandomAccessCollection {
        func indexed() -> IndexedCollection {
            IndexedCollection(base: self)
        }
    }

1 Ответ

0 голосов
/ 09 апреля 2020

Спасибо @ jordanpittman за предложение исправления:

ItemsView(items: $store.data[selectedFolderIndex!].items).id(selectedRowIndex)

Источник: https://swiftui-lab.com/swiftui-id

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...