Xcode error: The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
Xcode error: The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
当使用 Xcode 13.2.1 和 SwiftUI 实现简单的幻灯片放映时,我遇到了一个编译时错误,其中 Xcode 在我的 M1 上花费了大约 5 分钟来决定它无法解析我的代码,并最终给我错误:
The compiler is unable to type-check this expression in reasonable
time; try breaking up the expression into distinct sub-expressions
我将其缩小到底部附近的 NavigationLink 行。如果我将其注释掉,它会快速编译,只会出现警告。
以下是我的最小可重现示例:
import SwiftUI
import Foundation
enum MarkerType: Double {
case unlabeled = -99
case end = -4
case start = -3
case stop = -2
case blank = -1
case image = 1
}
class LabeledImage {
let image: Image
let marker: Double
var appeared = false
init(image: Image, marker: Double) {
self.image = image
self.marker = marker
}
}
struct SlideShow {
private let maxImages: Int = 10000
var images = [LabeledImage]()
var labels = [String]()
var totalImages: Int { return self.images.count }
private var fromFolder: URL
init(fromURL: URL = Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/DefaultImages")) {
self.fromFolder = fromURL
}
}
class AppState: ObservableObject {
static var docDir: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
@Published var isMainMenuActive = false
@Published var loadFolder: URL = Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/DefaultImages")
@Published var intervalSeconds: Double = 0.6
var saveFolder = URL(fileURLWithPath: "BCILab", relativeTo: docDir)
var labels = [String]()
var totalImages: Int = 0
var saveIndex: Int = 0
}
struct minsample: View {
@StateObject private var appState = AppState()
@State private var slideshow = SlideShow()
@State private var selection: Int = 0
private func insertAppears(_ marker: Double) {
let nmarker = marker + 100.0
}
var body: some View {
NavigationView {
ForEach(0..<slideshow.images.count-1, id: \.self) { i in
let thisImage = slideshow.images[i].image
.resizable()
.aspectRatio(contentMode: .fit)
.onAppear(perform: { insertAppears(slideshow.images[i].marker) })
let nextImage = slideshow.images[i+1].image
.resizable()
.aspectRatio(contentMode: .fit)
.onAppear(perform: { insertAppears(slideshow.images[i+1].marker) })
NavigationLink(destination: nextImage, tag: i, selection: self.$selection) { thisImage }
}
}
}
}
通常,在 ForEach
中使用 index-based 解决方案不是一个好主意。它破坏了 SwiftUI 的视图差异系统,并且往往会导致 compile-time 问题。
我先做 LabeledImage
Identifiable
:
class LabeledImage : Identifiable {
var id = UUID()
let image: Image
let marker: Double
var appeared = false
init(image: Image, marker: Double) {
self.image = image
self.marker = marker
}
}
(我也会将其设为 struct
——稍后会详细介绍)
然后,由于您确实需要索引来实现您的 nextImage
功能,您可以在集合上使用 .enumerated
:
struct MinSample: View {
@StateObject private var appState = AppState()
@State private var slideshow = SlideShow()
@State private var selection: Int? = 0
private func insertAppears(_ marker: Double) {
let nmarker = marker + 100.0
}
var body: some View {
NavigationView {
ForEach(Array(slideshow.images.enumerated()), id: \.1.id) { (index,imageModel) in
if index < slideshow.images.count - 1 {
let thisImage = imageModel.image
.resizable()
.aspectRatio(contentMode: .fit)
.onAppear(perform: { insertAppears(imageModel.marker) })
let nextImage = slideshow.images[index + 1].image
.resizable()
.aspectRatio(contentMode: .fit)
.onAppear(perform: { insertAppears(slideshow.images[index+1].marker) })
NavigationLink(destination: nextImage, tag: index, selection: self.$selection) { thisImage }
} else {
EmptyView()
}
}
}
}
}
上面的代码在我的 M1 上编译很快,没有任何问题。
现在,不 directly-related 解决您的问题,但我会更改其他一些内容:
- 制作您的模型
struct
s,SwiftUI 在进行状态比较时通常可以更好地处理模型
- 不要存储对 SwiftUI
Image
s 的引用——而是存储对路径的引用或以其他方式重新创建该图像。无论如何,这将使 LabeledImage
到 struct
的过渡更加容易。因此,您的模型可能如下所示:
struct LabeledImage : Identifiable {
var id = UUID()
let imageName: String
let marker: Double
var appeared = false
}
- 考虑您是否需要
NavigationLink
中的 tag
和 selection
参数——也许在最小示例中不清楚为什么要使用它们。
当使用 Xcode 13.2.1 和 SwiftUI 实现简单的幻灯片放映时,我遇到了一个编译时错误,其中 Xcode 在我的 M1 上花费了大约 5 分钟来决定它无法解析我的代码,并最终给我错误:
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
我将其缩小到底部附近的 NavigationLink 行。如果我将其注释掉,它会快速编译,只会出现警告。
以下是我的最小可重现示例:
import SwiftUI
import Foundation
enum MarkerType: Double {
case unlabeled = -99
case end = -4
case start = -3
case stop = -2
case blank = -1
case image = 1
}
class LabeledImage {
let image: Image
let marker: Double
var appeared = false
init(image: Image, marker: Double) {
self.image = image
self.marker = marker
}
}
struct SlideShow {
private let maxImages: Int = 10000
var images = [LabeledImage]()
var labels = [String]()
var totalImages: Int { return self.images.count }
private var fromFolder: URL
init(fromURL: URL = Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/DefaultImages")) {
self.fromFolder = fromURL
}
}
class AppState: ObservableObject {
static var docDir: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
@Published var isMainMenuActive = false
@Published var loadFolder: URL = Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/DefaultImages")
@Published var intervalSeconds: Double = 0.6
var saveFolder = URL(fileURLWithPath: "BCILab", relativeTo: docDir)
var labels = [String]()
var totalImages: Int = 0
var saveIndex: Int = 0
}
struct minsample: View {
@StateObject private var appState = AppState()
@State private var slideshow = SlideShow()
@State private var selection: Int = 0
private func insertAppears(_ marker: Double) {
let nmarker = marker + 100.0
}
var body: some View {
NavigationView {
ForEach(0..<slideshow.images.count-1, id: \.self) { i in
let thisImage = slideshow.images[i].image
.resizable()
.aspectRatio(contentMode: .fit)
.onAppear(perform: { insertAppears(slideshow.images[i].marker) })
let nextImage = slideshow.images[i+1].image
.resizable()
.aspectRatio(contentMode: .fit)
.onAppear(perform: { insertAppears(slideshow.images[i+1].marker) })
NavigationLink(destination: nextImage, tag: i, selection: self.$selection) { thisImage }
}
}
}
}
通常,在 ForEach
中使用 index-based 解决方案不是一个好主意。它破坏了 SwiftUI 的视图差异系统,并且往往会导致 compile-time 问题。
我先做 LabeledImage
Identifiable
:
class LabeledImage : Identifiable {
var id = UUID()
let image: Image
let marker: Double
var appeared = false
init(image: Image, marker: Double) {
self.image = image
self.marker = marker
}
}
(我也会将其设为 struct
——稍后会详细介绍)
然后,由于您确实需要索引来实现您的 nextImage
功能,您可以在集合上使用 .enumerated
:
struct MinSample: View {
@StateObject private var appState = AppState()
@State private var slideshow = SlideShow()
@State private var selection: Int? = 0
private func insertAppears(_ marker: Double) {
let nmarker = marker + 100.0
}
var body: some View {
NavigationView {
ForEach(Array(slideshow.images.enumerated()), id: \.1.id) { (index,imageModel) in
if index < slideshow.images.count - 1 {
let thisImage = imageModel.image
.resizable()
.aspectRatio(contentMode: .fit)
.onAppear(perform: { insertAppears(imageModel.marker) })
let nextImage = slideshow.images[index + 1].image
.resizable()
.aspectRatio(contentMode: .fit)
.onAppear(perform: { insertAppears(slideshow.images[index+1].marker) })
NavigationLink(destination: nextImage, tag: index, selection: self.$selection) { thisImage }
} else {
EmptyView()
}
}
}
}
}
上面的代码在我的 M1 上编译很快,没有任何问题。
现在,不 directly-related 解决您的问题,但我会更改其他一些内容:
- 制作您的模型
struct
s,SwiftUI 在进行状态比较时通常可以更好地处理模型 - 不要存储对 SwiftUI
Image
s 的引用——而是存储对路径的引用或以其他方式重新创建该图像。无论如何,这将使LabeledImage
到struct
的过渡更加容易。因此,您的模型可能如下所示:
struct LabeledImage : Identifiable {
var id = UUID()
let imageName: String
let marker: Double
var appeared = false
}
- 考虑您是否需要
NavigationLink
中的tag
和selection
参数——也许在最小示例中不清楚为什么要使用它们。