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

NavigationLink跳转崩溃:关联Core Data的NavigationDestination触发异常

问题描述

我正在开发一款基于SwiftUI和Core Data的应用,使用NavigationStack与NavigationLink构建导航框架,目前使用无数据依赖的占位视图。但遇到如下问题:
初始视图 → 占位视图A(点击NavigationLink失败)→ 占位视图B → 接收Core Data查询结果作为参数的视图。
占位视图B中的NavigationDestination指向关联Core Data参数的目标视图,点击NavigationLink后界面冻结,内存占用持续上升,CPU使用率跳至99%。移除SecondView中results[0].property改用普通文本视图则恢复正常;将关联Core Data参数的目标视图移至初始视图也可正常运行。

可复现错误的简化代码:

import Foundation
import CoreData
import SwiftUI

@main
struct TestCrashAppApp: App {
    @StateObject private var dataController: DataController = DataController()
    @StateObject var navigationHandler = NavigationHandler()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, dataController.container.viewContext)
                .environmentObject(navigationHandler)
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var pathManager: NavigationHandler
    @FetchRequest(sortDescriptors: []) var results: FetchedResults<MyEntity>
    
    var body: some View {
        NavigationStack {
            VStack {
                NavigationLink("Test Link", value: 1)
            }
            .padding()
            .navigationDestination(for: Int.self) { int in
                SecondView()
            }
        }
    }
}

struct SecondView: View {
    @FetchRequest(sortDescriptors: []) var results: FetchedResults<MyEntity>
    
    var body: some View {
        NavigationLink("Test Other Link", value: "")
            .navigationDestination(for: String.self) { str in
                Text("\(results[0].property)")
            }
    }
}

class DataController: ObservableObject {
    let container = NSPersistentContainer(name: "TestModel")
    
    init() {
        container.loadPersistentStores { description, error in
            if let error = error {
                print("Core Data failed to load: \(error.localizedDescription)")
                return
            }
            
            self.container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
        }
    }
}

class NavigationHandler: ObservableObject {
    @Published var path = NavigationPath()
    
    func reset() {
        path = NavigationPath()
    }
    
    func goBack() {
        path.removeLast(1)
    }
}

注:TestModel包含一个实体MyEntity,带有单个Int16类型的属性property。

解决方案

核心问题原因

navigationDestination的闭包在初始化时会尝试解析results[0].property,这个操作会触发SwiftUI的视图更新循环,再加上直接访问数组索引可能引发的潜在数据加载问题,最终导致无限刷新、资源耗尽。

方案一:传递Core Data实体作为导航值

  1. 让Core Data实体遵循Hashable协议(NavigationLink的value要求可哈希):
extension MyEntity: Hashable {
    public static func == (lhs: MyEntity, rhs: MyEntity) -> Bool {
        lhs.objectID == rhs.objectID
    }
    
    public func hash(into hasher: inout Hasher) {
        hasher.combine(objectID)
    }
}
  1. 修改SecondView,先判断数据存在性,再传递实体:
struct SecondView: View {
    @FetchRequest(sortDescriptors: []) var results: FetchedResults<MyEntity>
    
    var body: some View {
        if let targetEntity = results.first {
            NavigationLink("Test Other Link", value: targetEntity)
                .navigationDestination(for: MyEntity.self) { entity in
                    Text("\(entity.property)")
                }
        } else {
            Text("暂无数据")
        }
    }
}

方案二:在目标视图中独立执行Core Data查询

将依赖Core Data的逻辑移到独立的目标视图中,避免在navigationDestination闭包中直接访问FetchedResults:

// 新建独立的目标视图
struct FinalView: View {
    @FetchRequest(sortDescriptors: []) var results: FetchedResults<MyEntity>
    
    var body: some View {
        if let entity = results.first {
            Text("\(entity.property)")
        } else {
            Text("暂无数据")
        }
    }
}

// 修改SecondView
struct SecondView: View {
    var body: some View {
        NavigationLink("Test Other Link", value: "")
            .navigationDestination(for: String.self) { str in
                FinalView()
            }
    }
}

关键注意事项

  • 永远不要直接使用results[0]访问Core Data查询结果,必须先通过results.first判断数据是否存在,避免数组越界错误。
  • 避免在navigationDestination闭包中执行依赖状态或异步数据的操作,闭包的求值逻辑会被SwiftUI提前处理,容易触发无限刷新循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 06:40:36