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

Swift代码中"The compiler is unable to typecheck..."错误排查求助

Swift编译错误:The compiler is unable to typecheck this expression in reasonable time 解决方法

我在Swift代码中遇到编译错误:The compiler is unable to typecheck this expression in reasonable time,错误标记在TimeMaxChart的body属性处。尝试过拆分表达式、指定静态类型等方法,问题仍未解决,相关代码如下:

import SwiftUI
import Charts

struct TimeMaxChart: View {
    
    @Environment(\.managedObjectContext) private var viewContext
    
    // Fetching profile to check if its metric
    @FetchRequest(entity: Profile.entity(), sortDescriptors: []) private var profileResults: FetchedResults<Profile>
    
    // Fetching BodyWeightentries
    @FetchRequest(entity: BodyEntry.entity(),
                  sortDescriptors: [NSSortDescriptor(keyPath: \BodyEntry.dateAchieved, ascending: false)]
    ) private var bodyEntryResults: FetchedResults<BodyEntry>
    
    // For the fetched prs for the exercise
    @FetchRequest private var timeMaxResults: FetchedResults<TimeMax>
    
    // State to toggle the bodyweight overlay graph off and on
    @State var overlayBodyWeight: Bool = false
    
    let exercise: TimeBasedExercise
    
    // Constructor to inject the correct exercise into the fetchRequest.
    init(exercise: TimeBasedExercise) {
        self.exercise = exercise
        
        self._timeMaxResults = FetchRequest<TimeMax>(
            entity: TimeMax.entity(),
            sortDescriptors: [NSSortDescriptor(keyPath: \TimeMax.achievedOnDate, ascending: false)],
            predicate: NSPredicate(format: "exercise == %@", exercise)
        )
    }
    
    var body: some View { // <-- ERROR MARKED HERE
        
        // Get the profile from the fetchResults
        let profile: Profile = profileResults.first!
        let weightUnit: String = profile.isMetric ? "kg's" : "lbs"
        
        // Get the highest 1RM pr recorded on the exercise
        let highestTimeMaxPrByLoad: TimeMax? = timeMaxResults.max(by: {$0.weightLoad < $1.weightLoad})?
        let highestTimeMaxLoad: Double = highestTimeMaxPrByLoad?.weightLoad ?? 0
        
        // Get the highest bodyweight recorded
        let highestBwEntry: BodyEntry? = bodyEntryResults.max(by: {$0.bodyWeight < $1.bodyWeight})?
        let highestBw: Double = highestBwEntry?.bodyWeight ?? 0
        
        // Compare and chose the one who has the biggest value, this is later used to scale the y axis correctly
        let loadHigherThanBw: Bool = highestTimeMaxLoad >= highestBw
        let highestOfLoadAndBw: Double = loadHigherThanBw ? highestTimeMaxLoad : highestBw
        
        // Highest amrap count
        let highestTimeMaxByTime: TimeMax? = timeMaxResults.max(by: {$0.prQuantity < $1.prQuantity})?
        let highestTimeMaxTime: Double = highestTimeMaxByTime?.prQuantity ?? 0
        
        (
            Text("Time-max")
                .font(.subheadline)
                .fontWeight(.bold)
            + Text(" chart for ")
                .font(.subheadline)
            + Text(exercise.exerciseName!)
                .font(.subheadline)
                .fontWeight(.bold)
        )
        .padding(.horizontal, 40)
        .padding(.top, 20)
        
        VStack(alignment: .leading) {
            LightSubHeadline(text: "load (\(weightUnit)) at timed set (Blue)")
            LightSubHeadline(text: "timed set pr in seconds (Black)")
            LightSubHeadline(text: "bodyweight (\(weightUnit)) (Yellow)")
        }
        
        ZStack {
            
            Rectangle()
                .cornerRadius(10)
                .foregroundStyle(Color(.systemGray6))
                .frame(height: 385)
                .padding(.horizontal, 40)
            
            if timeMaxResults.isEmpty {
                Text("Cant genereate this chart because there are no Time PR's recorded for exercise: \(exercise.exerciseName!)")
                    .font(.subheadline)
                    .fontWeight(.light)
                    .foregroundColor(.red)
                    .padding(.all, 80)
                    .multilineTextAlignment(.center)
                
            } else {
                VStack {
                    Chart {
                        ForEach(timeMaxResults) {
                            LineMark (
                                x: .value("prDate", $0.achievedOnDate!),
                                y: .value("load", $0.weightLoad),
                                series: .value("load", "A")
                            )
                            .foregroundStyle(.blue)
                        }
                        
                        if overlayBodyWeight {
                            ForEach(bodyEntryResults) {
                                LineMark (
                                    x: .value("bwDate", $0.dateAchieved!),
                                    y: .value("bw", $0.bodyWeight),
                                    series: .value("bw", "C")
                                )
                                .foregroundStyle(.yellow)
                            }
                        }
                    }
                    .padding(.horizontal, 50)
                    .chartYScale(domain: 0...highestOfLoadAndBw + 20)
                    .frame(height: 150)
                    
                    Chart {
                        ForEach(timeMaxResults) {
                            LineMark (
                                x: .value("prDate", $0.achievedOnDate!),
                                y: .value("time", $0.time),
                                series: .value("reps", "B")
                            )
                            .foregroundStyle(.black)
                            
                            PointMark (
                                x: .value("prDate", $0.achievedOnDate!),
                                y: .value("time", $0.time)
                            )
                            .foregroundStyle(.black)
                            
                            }
                        }
                        .padding(.horizontal, 50)
                        .chartYScale(domain: 0...highestTimeMaxTime + 20)
                        .frame(height: 150)
                    
                    Toggle(isOn: $overlayBodyWeight, label: {
                        Text("Do you want to overlay bodyweight?")
                    })
                    .padding(.horizontal, 50)
                    .padding(.top, 10)
                    
                }
            }
        }
    }
}


#Preview {
        
    let context = PersistenceController.preview.container.viewContext
    
    @FetchRequest(entity: TimeBasedExercise.entity(), sortDescriptors: []) var exerciseResults: FetchedResults<TimeBasedExercise>

    let exercise = exerciseResults.first
    
    return TimeMaxChart(exercise: exercise!)
        .environment(\.managedObjectContext, context)
}

核心问题与修复步骤

  1. body必须返回单个View
    你的body中直接并列了多个视图(文本组合、说明VStack、ZStack),SwiftUI要求body返回单个View类型,这种写法会让编译器进行复杂的类型推导,最终超时。必须用外层容器(比如VStack)包裹所有子视图。

  2. 移除多余语法符号
    代码中多处max(by:)调用后多了一个多余的问号,比如:

    let highestTimeMaxPrByLoad: TimeMax? = timeMaxResults.max(by: {$0.weightLoad < $1.weightLoad})?
    

    max(by:)本身返回可选类型,不需要额外加问号,直接移除即可,否则会导致类型不匹配和推导负担。

  3. 抽离计算逻辑到私有方法
    将body内的变量计算逻辑(比如获取最大重量、体重等)抽成私有方法,减少body内的代码复杂度,降低编译器推导压力。

  4. 避免强制解包
    代码中大量使用!强制解包(比如profileResults.first!、exercise.exerciseName!),不仅会导致运行时崩溃,也会增加编译器类型推导难度,建议用if let或guard let处理可选值。

修复后的关键代码示例

抽离计算方法

private func calculateWeightUnit() -> String {
    guard let profile = profileResults.first else { return "kg's" }
    return profile.isMetric ? "kg's" : "lbs"
}

private func highestTimeMaxLoad() -> Double {
    let highestPr = timeMaxResults.max(by: {$0.weightLoad < $1.weightLoad})
    return highestPr?.weightLoad ?? 0
}

private func highestBodyWeight() -> Double {
    let highestEntry = bodyEntryResults.max(by: {$0.bodyWeight < $1.bodyWeight})
    return highestEntry?.bodyWeight ?? 0
}

private func highestOfLoadAndBw() -> Double {
    let load = highestTimeMaxLoad()
    let bw = highestBodyWeight()
    return max(load, bw)
}

private func highestTimeMaxTime() -> Double {
    let highestPr = timeMaxResults.max(by: {$0.prQuantity < $1.prQuantity})
    return highestPr?.prQuantity ?? 0
}

重构后的body

var body: some View {
    VStack { // 外层容器包裹所有视图
        (
            Text("Time-max")
                .font(.subheadline)
                .fontWeight(.bold)
            + Text(" chart for ")
                .font(.subheadline)
            + Text(exercise.exerciseName ?? "Unknown Exercise") // 替换强制解包
                .font(.subheadline)
                .fontWeight(.bold)
        )
        .padding(.horizontal, 40)
        .padding(.top, 20)
        
        VStack(alignment: .leading) {
            LightSubHeadline(text: "load (\(calculateWeightUnit())) at timed set (Blue)")
            LightSubHeadline(text: "timed set pr in seconds (Black)")
            LightSubHeadline(text: "bodyweight (\(calculateWeightUnit())) (Yellow)")
        }
        
        ZStack {
            // 原ZStack内容保持不变
            Rectangle()
                .cornerRadius(10)
                .foregroundStyle(Color(.systemGray6))
                .frame(height: 385)
                .padding(.horizontal, 40)
            
            if timeMaxResults.isEmpty {
                Text("Cant genereate this chart because there are no Time PR's recorded for exercise: \(exercise.exerciseName ?? "Unknown")")
                    .font(.subheadline)
                    .fontWeight(.light)
                    .foregroundColor(.red)
                    .padding(.all, 80)
                    .multilineTextAlignment(.center)
                
            } else {
                VStack {
                    Chart {
                        ForEach(timeMaxResults) { entry in
                            LineMark (
                                x: .value("prDate", entry.achievedOnDate!),
                                y: .value("load", entry.weightLoad),
                                series: .value("load", "A")
                            )
                            .foregroundStyle(.blue)
                        }
                        
                        if overlayBodyWeight {
                            ForEach(bodyEntryResults) { entry in
                                LineMark (
                                    x: .value("bwDate", entry.dateAchieved!),
                                    y: .value("bw", entry.bodyWeight),
                                    series: .value("bw", "C")
                                )
                                .foregroundStyle(.yellow)
                            }
                        }
                    }
                    .padding(.horizontal, 50)
                    .chartYScale(domain: 0...highestOfLoadAndBw() + 20)
                    .frame(height: 150)
                    
                    Chart {
                        ForEach(timeMaxResults) { entry in
                            LineMark (
                                x: .value("prDate", entry.achievedOnDate!),
                                y: .value("time", entry.time),
                                series: .value("reps", "B")
                            )
                            .foregroundStyle(.black)
                            
                            PointMark (
                                x: .value("prDate", entry.achievedOnDate!),
                                y: .value("time", entry.time)
                            )
                            .foregroundStyle(.black)
                        }
                    }
                    .padding(.horizontal, 50)
                    .chartYScale(domain: 0...highestTimeMaxTime() + 20)
                    .frame(height: 150)
                    
                    Toggle(isOn: $overlayBodyWeight, label: {
                        Text("Do you want to overlay bodyweight?")
                    })
                    .padding(.horizontal, 50)
                    .padding(.top, 10)
                }
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:42:34