列表不在 DestinationView 中传播更新

问题描述

一旦详细视图完全呈现,时钟将冻结。

如果您用 List/ScrollView 替换 vstack,传播将会流动。

struct ContentView: View {

    @State private var clocks = [Date(),Date(),Date()]
    
    var body: some View {
        NavigationView {
            List {
                ForEach(clocks.indices) { idx in
                    NavigationLink(destination: Text(clocks[idx],formatter: formatter)) {
                        Text("Counter \(idx)")
                    }
                }
            }
        }
        .onReceive(Timer.publish(every: 1,on: .main,in: .default).autoconnect()) {
            clocks[0] = $0
            clocks[1] = $0
            clocks[2] = $0
        }
    }
    
    var formatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.timeStyle = .medium
        return formatter
    }
}

解决方法

您的目的地 (Text) 只是从 Date 捕捉静态时刻 (clocks),并且没有意识到它正在更新这一事实。

为什么在 List 而不是 ScrollView 中发生这种情况有点神秘,但我假设 SwiftUI 正在幕后做一些事情来尝试确定如果 List 行是相同的,并且如果它认为不需要重新渲染它们,为了效率,ScrollViewVStack 不会这样做。

这是一个可能的解决方案,它使用 ObservableObject 视图模型在视图之间传递数据并通过 Published 属性保持更新。

class ViewModel : ObservableObject {
    @Published var time = Date()
    @Published var clocks = [Date(),Date(),Date()]
    
    var cancellable : AnyCancellable?
    
    init() {
        cancellable = Timer.publish(every: 1,on: .main,in: .default)
            .autoconnect()
            .sink { (date) in
                self.clocks[0] = date
                self.clocks[1] = date
                self.clocks[2] = date
                print(date)
            }
    }
}

struct ContentView: View {

    @ObservedObject var viewModel = ViewModel()
    
    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.clocks.indices) { idx in
                    NavigationLink(destination: DetailView(index: idx,viewModel: viewModel)) {
                        Text("Counter \(idx)")
                    }
                }
            }
        }.navigationViewStyle(StackNavigationViewStyle())
    }

}

struct DetailView : View {
    var index : Int
    @ObservedObject var viewModel : ViewModel
    
    var body: some View {
        Text(viewModel.clocks[index],formatter: formatter)
    }
    
    var formatter: DateFormatter {
            let formatter = DateFormatter()
            formatter.timeStyle = .medium
            return formatter
        }
}