Cuando uso Xcode 13.2.1 y SwiftUI para implementar una presentación de diapositivas simple, aparece un error de tiempo de compilación en el que Xcode tarda unos 5 minutos en mi M1 para decidir que no puede analizar mi código y, finalmente, me da el error:
El compilador no puede verificar el tipo de esta expresión en un tiempo razonable; intente dividir la expresión en distintas subexpresiones
Lo reduje hasta la línea NavigationLink cerca de la parte inferior. Si comento eso, se compila rápidamente con solo una advertencia.
El siguiente es mi ejemplo mínimo y reproducible:
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 } } } } }
Generalmente, usar una solución basada en índices en ForEach
es una mala idea. Rompe el sistema de SwiftUI para diferenciar las vistas y también tiende a generar problemas de tiempo de compilación.
Comenzaría haciendo 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 } }
(También lo convertiría en una struct
, más sobre eso más adelante)
Luego, dado que necesita índices para lograr su funcionalidad nextImage
, puede usar .enumerated
en la colección:
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() } } } } }
Lo anterior se compila rápidamente en mi M1 sin problemas.
Ahora, no está directamente relacionado con su problema, pero hay algunas otras cosas que cambiaría:
struct
s, que SwiftUI generalmente trata mucho mejor al hacer comparaciones de estadoImage
s; en su lugar, almacene una referencia a una ruta o alguna otra forma de recrear esa imagen. Eso hará que la transición de LabeledImage
a una struct
sea más fácil de todos modos. Entonces, su modelo podría verse así: struct LabeledImage : Identifiable { var id = UUID() let imageName: String let marker: Double var appeared = false }
tag
y los parámetros de selection
en su NavigationLink
; tal vez no esté claro en el ejemplo mínimo por qué se usan.