#ios #swift #swiftui #tabview
#iOS #swift #swiftui #tabview
Вопрос:
SwiftUI TabView содержит до двух вкладок. Каждый отображает данные из одной и той же модели. Если данные отсутствуют, отображается progressView, если данные присутствуют, отображается текущее значение. В примере модели данные устанавливаются асинхронно через 2 секунды, что вызывает проблему. (В моем реальном приложении данные устанавливаются в результате асинхронного вызова.)
После запуска приложения отображается первая вкладка, содержащая progressView, и данные отображаются через 2 секунды. Пока все, кажется, работает. При переключении с первой вкладки на вторую приложение вылетает где-то на глубине 75 уровней в коде отображения SwiftUI:
(AG::Graph::add_indirect_attribute:) с EXC_BAD_ACCESS .
Что я делаю не так и как я могу обойти проблему, если это ошибка SwiftUI?
Следующий код вызывает сбой:
import SwiftUI
import Combine
class Model: ObservableObject{
@Published var value:Double?
init(){
DispatchQueue.main.asyncAfter(deadline: .now() 3){
self.value = 2.0
print("value set")
}
}
}
@main
struct TabViewUpdatingTestApp: App {
@StateObject var model = Model()
var body: some Scene {
WindowGroup {
ContentView(model: model)
}
}
}
struct Tab: View {
let name:String
@ObservedObject var model:Model
var body: some View {
if let mvalue = model.value{
Text("name: (name), value: (mvalue)")
}else{
ProgressView().font(.largeTitle)
}
}
}
struct ContentView: View {
@ObservedObject var model:Model
var body: some View {
TabView {
Tab(name: "Tab 1", model: model)
.tabItem {
Label("Tab 1", systemImage: "1.circle")
}
Tab(name: "Tab 2", model: model)
.tabItem {
Label("Tab 2", systemImage: "2.circle")
}
}
}
}
Ответ №1:
Для меня это похоже на ошибку. Возможным обходным решением может быть принудительное обновление TabView
:
struct ContentView: View {
@ObservedObject var model: Model
var body: some View {
TabView {
Tab(name: "Tab 1", model: model)
.tabItem {
Label("Tab 1", systemImage: "1.circle")
}
Tab(name: "Tab 2", model: model)
.tabItem {
Label("Tab 2", systemImage: "2.circle")
}
}
.id(model.value) // add here
}
}
В качестве альтернативы, вместо того, чтобы перерисовывать представление при model.value
изменениях, вы можете создать какую-либо другую переменную, которая изменяется только один раз (поэтому вы обновляете ее не TabView
каждый раз, а только один раз в начале).
Комментарии:
1. Спасибо! Это предотвращает сбой в моем реальном коде, и поскольку это значение устанавливается только один раз, нет опасности слишком большого количества перерисовок. Кроме того, я не знал о модификаторе id. В будущем может быть полезно выполнить некоторые принудительные перерисовки.