SwiftUI - удаление строки в NavigationView ненадежно обновляет подробное представление

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

import SwiftUI

/*
    Model
*/
struct Item: Identifiable, Hashable {
    let id = UUID()
    let date: Date
    let name: String
}

/*
    List view
*/
struct ContentView: View {
    
    @State var itemArray: [Item] = [
        Item(date: Date(), name: "Item 1"),
        Item(date: Date(), name: "Item 2"),
        Item(date: Date(), name: "Item 3")
    ]
    
    @State var selectedItem: Item?
    
    var body: some View {
        
        VStack {
            NavigationView  {
                List {
                    ForEach(itemArray, id: \.self) { item in
                        NavigationLink(
                            destination: DetailView(item: item),
                            tag: item,
                            selection: $selectedItem
                        ) {
                            Text("\(item.name)").font(.headline)
                        }
                        .contextMenu {
                            Button("Delete", action: {
                                delete(item)
                                //selectedItem = nil
                                //DispatchQueue.main.asyncAfter(deadline: .now() + 1) { delete(item) }
                            })
                        }
                    }
                    .onDelete() { offsets in
                        itemArray.remove(atOffsets: offsets)
                        //selectedItem = nil
                        //DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { itemStore.delete(offsets: offsets) }
                    }
                }
                
                // Uncommenting this provides a placeholder for the detail view but prevents onDelete on macOS
                //Text("Select item...")
            }
            
            Text(selectedItem?.name ?? "No selection")
        }
    }
    
    private func delete(_ item: Item) {
        var index: Int? = nil
        for i in 0..<itemArray.count {
            if item == itemArray[i] { index = i }
        }
        if index != nil { itemArray.remove(at: index!) }
    }
}

/*
    Detail view
*/
struct DetailView: View {
    var item: Item
    
    var body: some View {
        Text(item.name)
    }
}

Проблема возникает, когда элемент в списке удаляется, и есть два шаблона странного поведения в зависимости от того, присутствует ли заполнитель или нет:

Без заполнителя: (текст комментария (выберите элемент ...)):

Действие: выберите элемент 1 и удалите его (проведя пальцем по экрану или используя контекстное меню)
Результат: Ожидаемое поведение: подробное представление пусто. Фактическое поведение: подробный вид для элемента 1 все еще присутствует

С заполнителем:

Возникает ожидаемое поведение, но НЕ для последнего элемента в списке

Попытки обойти:

  1. Явно установить для выбора значение nil перед удалением - не удается
  2. Используйте индексы, как предложено здесь - не удается
  3. Обходной путь 1 с задержкой перед удалением - работает, но это взлом

Я тестировал это на macOS BigSur 11.2.3 и iPadOS 14.4.1 (в альбомной ориентации), и проблема одинакова для обеих платформ.

Мои вопросы:

  1. Это ошибка или я что-то упускаю?
  2. Есть ли надежный обходной путь?
  3. Как сделать так, чтобы удаление смахивания отображалось в macOS при наличии заполнителя?

person Bill Aylward    schedule 19.03.2021    source источник