SwiftUI用fullScreenCover传结构体无效但NavigationLink正常怎么解决
问题原因
你遇到的问题来自两个核心错误:
fullScreenCover(isPresented:)的内容闭包会在模态视图首次创建时捕获上下文的值,你初始定义的user是空的User()实例,哪怕后续Firebase异步回调中修改了user值再触发showHomeScreen,闭包捕获的依然是最早的空实例,无法拿到更新后的值。HomeView中用@State修饰传入的user属于错误用法:@State是SwiftUI专为视图内部私有状态设计的修饰符,外部传入的参数用@State修饰后,只会保留初始化时的初始值,不会同步父视图的后续修改。
解决方案(推荐)
改用SwiftUI专为传值场景设计的fullScreenCover(item:)重载实现,它会自动绑定可选类型的数据源,模态弹出时自动传入最新值:
第一步:修改注册页的属性声明
把原来分开定义的user和showHomeScreen合并为一个可选的User状态:
// 替换原来的@State var user = User()和@State var showHomeScreen = false @State var activeUser: User?
第二步:修改注册点击逻辑
Firebase回调赋值完成后直接给activeUser赋值即可触发模态弹出:
func handleRegisterTapped() { if self.password != confirmPassword { print("Error - Passwords don't match") self.showAlert = true return } print(self.email, self.password) Auth.auth().createUser(withEmail: self.email, password: self.password) { result, error in guard let id = result?.user.uid else { return } let newUser = User(id: id, fullName: self.fullName, email: self.email) do { let _ = try db.collection("Users").addDocument(from: newUser) // 直接赋值触发模态,不需要再操作showHomeScreen self.activeUser = newUser }catch { print(error) } } }
第三步:修改fullScreenCover声明
改用item版本的重载:
.fullScreenCover(item: $activeUser) { user in HomeView(user: user) }
第四步:修正HomeView的属性定义
去掉错误的@State修饰符,直接用普通常量接收传入的User即可:
struct HomeView: View { // 外部传入的只读参数不需要@State let user: User var body: some View { Text("Welcome, \(user.fullName ?? "")") } }
备选方案(不修改isPresented写法)
如果你一定要保留isPresented的用法,只需要把HomeView的user改成@Binding类型,保证读取的是父视图的实时值即可:
- 注册页的fullScreenCover传递Binding:
.fullScreenCover(isPresented: $showHomeScreen, content: { HomeView(user: $user) })
- 修改HomeView的属性声明:
struct HomeView: View { @Binding var user: User var body: some View { Text("Welcome, \(user.fullName ?? "")") } }
内容的提问来源于stack exchange,提问作者Osama Naeem
相关产品推荐
相关产品推荐

