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) }
核心问题与修复步骤
body必须返回单个View
你的body中直接并列了多个视图(文本组合、说明VStack、ZStack),SwiftUI要求body返回单个View类型,这种写法会让编译器进行复杂的类型推导,最终超时。必须用外层容器(比如VStack)包裹所有子视图。移除多余语法符号
代码中多处max(by:)调用后多了一个多余的问号,比如:let highestTimeMaxPrByLoad: TimeMax? = timeMaxResults.max(by: {$0.weightLoad < $1.weightLoad})?max(by:)本身返回可选类型,不需要额外加问号,直接移除即可,否则会导致类型不匹配和推导负担。抽离计算逻辑到私有方法
将body内的变量计算逻辑(比如获取最大重量、体重等)抽成私有方法,减少body内的代码复杂度,降低编译器推导压力。避免强制解包
代码中大量使用!强制解包(比如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
相关产品推荐
相关产品推荐

