Неожиданное поведение обновления представления - SwiftUI / Monterey
Следующий код вырезан из приложения, которое компилируется и работает под MacOS 11. Он показывает панель вкладок - щелчок по элементу выделяет его. Под панелью вкладок находится поле редактирования текста, в котором можно редактировать заголовок выбранной вкладки.
Есть 2 проблемы:
- Заголовок вкладки, отображаемый в редакторе заголовков, не совпадает по фазе с выбранной вкладкой.
- Независимо от того, какая вкладка выбрана, при редактировании заголовка всегда обновляется первая вкладка.
Я не уверен, что мне очень повезло, что этот код когда-либо работал в Big Sur, или возникла проблема с Монтереем. Я определенно не использую это как пример кода - я уверен, что есть более эффективные способы его реализации, но поинтересуйтесь, должно ли это работать.
import SwiftUI
class Document: ObservableObject {
var tabs = [Tab(id: 0), Tab(id: 1)]
@Published var activeTab: Int = 0
}
class Tab: ObservableObject, Identifiable {
let id: Int
@Published var title: String
init(id: Int) {
self.id = id
self.title = "Tab \(id)"
}
}
@main
struct Test: App {
@StateObject var document: Document = Document()
var body: some Scene {
WindowGroup {
ContentView()
.padding()
.environmentObject(document)
}
}
}
struct ContentView: View {
@EnvironmentObject var document: Document
var body: some View {
TabBar()
TabEditView(activeTab: document.tabs[document.activeTab])
}
}
struct TabEditView: View {
@EnvironmentObject var document: Document
@ObservedObject var activeTab: Tab
@State var title: String = ""
init(activeTab: Tab) {
print("CONSOLE - Init TabEditView for tab \(activeTab.id)")
self.activeTab = activeTab
}
var body: some View {
HStack {
Text("Tab title:")
TextField("Tab title:", text: $title, onCommit: { activeTab.title = title })
.onAppear { title = activeTab.title }
.onChange(of: document.activeTab) { _ in
print("CONSOLE - Updating TextField from tab \(activeTab.id)")
title = activeTab.title
}
}
}
}
struct TabBar: View {
@EnvironmentObject var document: Document
var body: some View {
HStack {
ForEach(document.tabs, content: TabItem.init)
}
}
}
struct TabItem: View {
@EnvironmentObject var document: Document
@ObservedObject var tab: Tab
init(_ tab : Tab) { self.tab = tab }
var body: some View {
Text(tab.title)
.padding(2)
.background(tab.id == document.activeTab ? .red : .clear)
.cornerRadius(4)
.onTapGesture {
document.activeTab = tab.id
}
}
}