You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中使用.navigationDestination(isPresented:)导航卡顿问题求助

SwiftUI .navigationDestination 导航卡顿问题解决

问题情况

使用.navigationDestination(isPresented:)跳转时,只要在目标视图NewComposeView的sendMessage闭包里调用viewModel相关方法(哪怕只是简单打印),导航就会出现卡顿。但注释掉闭包内的viewModel.sendMessage后,跳转恢复正常。

相关代码如下:

主视图代码

@State private var navigateToChatView = false
    
var body: some View {
        MyView()
            .navigationTitle("Users")
            .searchable(text: $viewModel.searchText)
            .navigationDestination(isPresented: $navigateToChatView) {
                if let selectedUser = selectedUsers.first, let name = selectedUser.name {
                    NewComposeView(sendMessage: { message in
                        viewModel.sendMessage(message: message) // 注释此行导航正常
                    })
                    .navigationTitle(name)
                }
            }
        }

NewComposeView代码

import SwiftUI

struct NewComposeView: View {
    @State private var message: String = ""
    var sendMessage: (String) -> Void

    var body: some View {
        HStack {
            ZStack {
                RoundedRectangle(cornerRadius: 18)
                    .stroke()
                HStack {
                    TextField("Write a message", text: $message)
                    Spacer()
                    Button {
                        sendMessage(message)
                        message = ""
                    } label: {
                        Image(systemName: "paperplane.fill")
                            .resizable()
                            .frame(width: 20, height: 20)
                            .font(.title)
                    }
                }
                .padding(EdgeInsets(top: 3, leading: 20, bottom: 3, trailing: 20))
            }
            .frame(height: 40)
        }
        .foregroundColor(Color(.white))
    }
}

问题根源

本质是闭包捕获了主视图中的viewModel,导致SwiftUI在导航跳转时需要处理主视图与目标视图间额外的状态绑定关系——哪怕只是在闭包里执行打印操作,只要捕获了viewModel,这种绑定关联就会存在,拖慢导航的渲染速度。

解决办法

办法1:改用 .navigationDestination(item:) 触发导航

将选中的用户作为可选对象,通过item触发导航,避免闭包直接捕获viewModel,逻辑更清晰的同时也能解决卡顿:

@State private var selectedUser: User? // 替换为你的实际用户类型
    
var body: some View {
        MyView()
            .navigationTitle("Users")
            .searchable(text: $viewModel.searchText)
            .navigationDestination(item: $selectedUser) { user in
                NewComposeView(sendMessage: { message in
                    viewModel.sendMessage(message: message)
                })
                .navigationTitle(user.name ?? "")
            }
        }

办法2:提前封装sendMessage逻辑,减少闭包捕获

在主视图中将发送消息的逻辑单独封装为方法,再将方法传递给NewComposeView,避免在导航闭包内直接捕获viewModel:

// 主视图内新增方法
private func sendMessageToUser(_ message: String) {
    viewModel.sendMessage(message: message)
}

var body: some View {
        MyView()
            .navigationTitle("Users")
            .searchable(text: $viewModel.searchText)
            .navigationDestination(isPresented: $navigateToChatView) {
                if let selectedUser = selectedUsers.first, let name = selectedUser.name {
                    NewComposeView(sendMessage: sendMessageToUser)
                    .navigationTitle(name)
                }
            }
        }

办法3:给ViewModel的方法添加@MainActor

虽然排除了异步调用的影响,但如果sendMessage内存在隐性的非主线操作,也可能导致UI卡顿。给该方法添加@MainActor确保其在主线执行:

// 在你的ViewModel中修改
@MainActor
func sendMessage(message: String) {
    // 原有业务逻辑
}

验证方式

修改后测试导航跳转,还可以在主视图和NewComposeView的body中添加print(self),观察是否存在不必要的重复渲染,确认问题是否解决。

内容的提问来源于stack exchange,提问作者Christian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 13:25:22