SwiftUI NavigationLink прерывается после удаления и вставки нового элемента ForEach
По какой-то причине моя NavigationLink не работает в определенных обстоятельствах:
Учитывая приведенный ниже код, выполните следующие действия:
- Нажмите «Войти», чтобы добавить учетную запись в список.
- Ударьте, чтобы открыть стек
- Проведите пальцем влево и нажмите Delete, чтобы удалить первый элемент списка.
- Снова нажмите "Войти" (должно быть помещено в стек, но этого не происходит)
- Коснитесь первой строки (должна надавить на стопку, но не нажимает)
Вот код:
import SwiftUI
class Account: ObservableObject, Identifiable, Equatable, Hashable {
let id: String
init(id: String) {
self.id = id
}
static func == (lhs: Account, rhs: Account) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
class AccountManager: ObservableObject {
@Published private (set) var isLoading: Bool = false
@Published private (set) var accounts: [Account] = []
init() {
load()
}
func load() {
isLoading = true
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
self.accounts = [ Account(id: UUID().uuidString) ]
self.isLoading = false
}
}
func add(account: Account) {
accounts.insert(account, at: 0)
}
func delete(at offsets: IndexSet) {
accounts.remove(atOffsets: offsets)
}
}
struct AccountManagerEnvironmentKey: EnvironmentKey {
static var defaultValue: AccountManager = AccountManager()
}
extension EnvironmentValues {
var accountManager: AccountManager {
get { return self[AccountManagerEnvironmentKey.self] }
set { self[AccountManagerEnvironmentKey.self] = newValue }
}
}
struct ContentView: View {
@Environment(\.accountManager) var accountManager
@State var isLoading: Bool = false
@State var accounts: [Account] = []
@State var selectedAccount: Account? = nil
var body: some View {
NavigationView() {
ZStack {
List {
ForEach(accounts) { account in
NavigationLink(
destination: Text(account.id),
tag: account,
selection: $selectedAccount
) {
Text(account.id)
}
}
.onDelete(perform: { offsets in
accountManager.delete(at: offsets)
})
}
if isLoading {
ProgressView("Loading...")
}
}
.navigationBarTitle("Accounts", displayMode: .inline)
.toolbar(content: {
ToolbarItem(placement: .primaryAction) {
Button("Sign In") {
let newAccount = Account(id: UUID().uuidString)
accountManager.add(account: newAccount)
selectedAccount = newAccount
}
}
})
.onReceive(accountManager.$isLoading) { value in
isLoading = value
}
.onReceive(accountManager.$accounts) { value in
accounts = value
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
Если я изменю действие кнопки для этого, она будет работать:
accountManager.add(account: newAccount)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
selectedAccount = newAccount
}
Но это похоже на серьезный взлом.