SwiftUI中如何在NavigationView的外部响应函数中触发视图跳转
问题核心原因
- 线程不匹配:网络请求的
onResponse回调默认在后台子线程执行,而SwiftUI的@State属性必须在主线程更新才能触发视图重绘,你直接在后台线程修改isActiveWelcomeView,系统不会触发跳转逻辑。 - 值类型拷贝问题:SwiftUI的
View是值类型,你将遵循LoginProtocol的FundTransferDashboard实例作为代理传递给网络层时,传递的是当前实例的值拷贝,后续回调触发的是拷贝对象的onResponse方法,修改的是拷贝对象的属性,和当前屏幕上渲染的视图实例没有关联,状态更新自然不会生效。
解决方案
推荐你将登录逻辑抽成独立的引用类型视图模型,避免值类型拷贝问题,同时确保状态更新在主线程执行,具体修改如下:
1. 定义视图模型类,遵循代理协议
import SwiftUI class LoginViewModel: ObservableObject, LoginProtocol { // 用@Published修饰跳转状态,更新时自动通知视图刷新 @Published var isActiveWelcomeView = false func doLogin() { // 这里发起网络请求,将当前视图模型实例作为代理传递 // 因为是类(引用类型),传递的是同一个实例,不会出现拷贝问题 替换为你的实际网络请求方法(delegate: self) } func onResponse(loginResponse: LoginResponseModel) { // 此处执行你的校验逻辑,校验通过后切换到主线程更新状态 DispatchQueue.main.async { self.isActiveWelcomeView = true } } }
2. 修改视图代码,绑定视图模型状态
struct FundTransferDashboard: View { // 用@StateObject持有引用类型的视图模型,生命周期和当前视图绑定 @StateObject private var vm = LoginViewModel() var body: some View { ZStack(alignment: .top) { NavigationView { VStack { Button(action: { vm.doLogin() }) { HStack { Image("lock") .resizable() .frame(width: 50, height: 50, alignment: .leading) .padding(10) Text("LOGIN") .padding(.leading, 40) .foregroundColor(.white) .font(.system(size: 25, weight: .bold)) .padding(10) Spacer() } } .frame(maxWidth: .infinity) // 绑定视图模型的跳转状态 NavigationLink("", destination: WelcomeView(), isActive: $vm.isActiveWelcomeView) } } } } }
补充说明
如果你不想引入视图模型,也可以直接将原来的代理回调替换为闭包回调,闭包会捕获当前视图的状态变量,避免值拷贝问题,同时在闭包内更新状态时切换到主线程即可。
内容的提问来源于stack exchange,提问作者Enamul Haque
相关产品推荐
相关产品推荐

