在SwiftUI中导航前的触发功能
我的应用程序显示ID列表。当您点击ID时,将打开详细信息视图,该ID用于从网络检索详细信息。我现在用一个在SwiftUI中导航前的触发功能,swiftui,Swiftui,我的应用程序显示ID列表。当您点击ID时,将打开详细信息视图,该ID用于从网络检索详细信息。我现在用一个onAppear修饰符来做这件事,但我对此不满意。它不是很干净,会引起其他各种问题。我特别希望在用户导航时触发viewModel中的一个函数 可以将以下代码粘贴到新的SwiftUI项目中: import SwiftUI let fleet = Fleet(registries: ["NCC-1031"]) struct Fleet { let registrie
onAppear
修饰符来做这件事,但我对此不满意。它不是很干净,会引起其他各种问题。我特别希望在用户导航时触发viewModel中的一个函数
可以将以下代码粘贴到新的SwiftUI项目中:
import SwiftUI
let fleet = Fleet(registries: ["NCC-1031"])
struct Fleet {
let registries: [String]
}
struct Starship {
let registry: String
let name: String
}
class StarshipViewModel: ObservableObject {
enum Mode {
case idle
case loading
case success(Starship)
}
@Published var mode: Mode = .idle
let registry: String
private var timer: Timer?
func fetchFromNetwork() {
self.mode = .loading
self.timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { _ in
let starship = Starship(
registry: "NCC-1031",
name: "Discovery"
)
self.mode = .success(starship)
})
}
init(registry: String) {
self.registry = registry
}
}
struct StarshipDetails: View {
@ObservedObject var viewModel: StarshipViewModel
var body: some View {
VStack {
switch self.viewModel.mode {
case .idle:
Text("Idle")
case .loading:
Text("Loading")
case .success(let starship):
Text("Name: \(starship.name)")
}
}
.onAppear(perform: {
viewModel.fetchFromNetwork()
})
}
}
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(fleet.registries, id: \.self) { registry in
NavigationLink(destination: self.makeDestination(from: registry)) {
Text(registry)
}
}
}
}
}
private func makeDestination(from registry: String) -> StarshipDetails {
let viewModel = StarshipViewModel(registry: registry)
// Don't do it here, because a network request will be done for the whole list
// viewModel.fetchFromNetwork()
let view = StarshipDetails(viewModel: viewModel)
return view
}
}
导航时如何运行fetchFromNetwork()
调用,但不使用appear
注意:我不能只使用带有动作的按钮,因为无法获取对viewModel的引用
事实上,我们可以。它不需要对viewModel进行任何附加引用
这是一个解决方案的演示,类似于之前引用的内容。使用Xcode 12.1/iOS 14.1进行测试
struct TestActionBeforeLink: View {
@State private var navigate = false
@State private var selectedRegistry: String = ""
var body: some View {
NavigationView {
List {
ForEach(fleet.registries, id: \.self) { registry in
Button(action: {
self.selectedRegistry = registry
self.navigate = true
}) {
HStack {
Text(registry)
Spacer()
Image(systemName: "chevron.right") // if one needed
}
}
}
}
.background(
NavigationLink(destination: self.makeDestination(from: selectedRegistry), isActive: $navigate) {
EmptyView()
}
)
}
}
// no changes below, just removed comment
private func makeDestination(from registry: String) -> StarshipDetails {
let viewModel = StarshipViewModel(registry: registry)
let view = StarshipDetails(viewModel: viewModel)
return view
}
}