SwiftUI:编译器无法在合理的时间内对该表达式进行类型检查;尝试将表达式分解为不同的子表达式

SwiftUI: compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

所以我有一个 GeometryReader 封装了我的大部分 contentView,

struct ContentView: View {
    var body: some View {
        GeometryReader { proxy in 
            ....
        }
    }
}

但我 运行 遇到了问题。我将它毫无问题地传递到我的 ContentView 中的各种视图中。但是出于某种原因,如果我尝试将它传递到应用程序中 if 语句中定义的一组特定视图中,我会收到错误消息“编译器无法在合理的时间内对该表达式进行类型检查;请尝试将表达式分解为不同的子表达式”。问题似乎源于向此视图添加更多变量(proxy、proxyOffsetTop 或 proxyOffsetBottom)(不知道为什么):

import Foundation
import SwiftUI
import Mapbox
struct SlideOverCard<Content: View>: View {
@ObservedObject var keyboardResponder = KeyboardResponder()
@GestureState private var dragState = DragState.inactive
@Binding var feedbackSubmitted: Bool
@Binding var position: CardPosition
var mapStyle: URL
//let proxy: GeometryProxy
var content: () -> Content
//    var proxyOffsetTop: CGFloat
//    var proxyOffsetBottom: CGFloat
var body: some View {
    let drag = DragGesture()
        .updating($dragState) { drag, state, transaction in
            state = .dragging(translation: drag.translation)
    }.onEnded(onDragEnded)

    if (self.position == CardPosition.bottom(UIScreen.main.bounds.height - (77.5)) || self.position == CardPosition.middle(UIScreen.main.bounds.height - (135))) && mapStyle == MGLStyle.outdoorsStyleURL {
        return VStack (spacing: 0) {
            Handle(mapStyle: self.mapStyle)
            self.content()
        }
        .frame(height: UIScreen.main.bounds.height)
        .background(Color.white)
        .cornerRadius(10.0)
        .shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
        .offset(y: self.position.offset + self.dragState.translation.height - keyboardResponder.currentHeight)
        .animation(self.dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
        .gesture(drag)
    }
        
    else if self.position == CardPosition.bottom(UIScreen.main.bounds.height - (77.5)) || self.position == CardPosition.middle(UIScreen.main.bounds.height - (135)) && mapStyle == MGLStyle.darkStyleURL {
        return VStack (spacing: 0) {
            Handle(mapStyle: self.mapStyle)
            self.content()
        }
        .frame(height: UIScreen.main.bounds.height)
        .background(Color.init(red: 15/255, green: 15/255, blue: 15/255))
        .cornerRadius(10.0)
        .shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
        .offset(y: self.position.offset + self.dragState.translation.height - keyboardResponder.currentHeight)
        .animation(self.dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
        .gesture(drag)
    }
    
    else if mapStyle == MGLStyle.darkStyleURL {
        return VStack (spacing: 0) {
            Handle(mapStyle: self.mapStyle)
            self.content()
        }
        .frame(height: UIScreen.main.bounds.height)
        .background(Color.init(red: 15/255, green: 15/255, blue: 15/255))
        .cornerRadius(10.0)
        .shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
        .offset(y: self.position.offset + self.dragState.translation.height)
        .animation(self.dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
        .gesture(drag)
    }
    
    else {
        return VStack (spacing: 0) {
            Handle(mapStyle: self.mapStyle)
            self.content()
        }
        .frame(height: UIScreen.main.bounds.height)
        .background(Color.white)
        .cornerRadius(10.0)
        .shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
        .offset(y: self.position.offset + self.dragState.translation.height)
        .animation(self.dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
        .gesture(drag)
    }
}

private func onDragEnded(drag: DragGesture.Value) {
    let verticalDirection = drag.predictedEndLocation.y - drag.location.y
    let cardTopEdgeLocation = self.position.offset + drag.translation.height
    let positionAbove: CardPosition
    let positionBelow: CardPosition
    let closestPosition: CardPosition
    if cardTopEdgeLocation <= CardPosition.middle(UIScreen.main.bounds.height - (135)).offset {
        positionAbove = .top(50)
        positionBelow = .middle(UIScreen.main.bounds.height - (135))
        self.feedbackSubmitted = false
    } else {
        positionAbove = .middle(UIScreen.main.bounds.height - (135))
        positionBelow = .bottom(UIScreen.main.bounds.height - (77.5))
        self.feedbackSubmitted = false
    }
    if (cardTopEdgeLocation - positionAbove.offset) < (positionBelow.offset - cardTopEdgeLocation) {
        closestPosition = positionAbove
    } else {
        closestPosition = positionBelow
    }
    if verticalDirection > 0 {
        self.position = positionBelow
    } else if verticalDirection < 0 {
        self.position = positionAbove
    } else {
        self.position = closestPosition
    }
}
}

enum RelativeCardPosition {
case top
case middle
case bottom
}

struct CardPosition: Equatable {
let relativeCardPosition: RelativeCardPosition
let offset: CGFloat

static func top(_ offset: CGFloat) -> CardPosition {
    CardPosition(relativeCardPosition: .top, offset: offset)
}

static func middle(_ offset: CGFloat) -> CardPosition {
    CardPosition(relativeCardPosition: .middle, offset: offset)
}

static func bottom(_ offset: CGFloat) -> CardPosition {
    CardPosition(relativeCardPosition: .bottom, offset: offset)
}
}

enum DragState {
case inactive
case dragging(translation: CGSize)
var translation: CGSize {
    switch self {
    case .inactive:
        return .zero
    case .dragging(let translation):
        return translation
    }
}
var isDragging: Bool {
    switch self {
    case .inactive:
        return false
    case .dragging:
        return true
    }
}
}

只要我将代理从我传递给它的视图中删除,应用程序就可以正常运行。我尝试将不同的视图分组,因为我想也许我达到了 10 视图的上限,但我很确定这不再是错误了......我不知道是什么导致了这个问题,有什么建议吗?

这里编译器的任务是找出生成的视图类型。考虑到代码有很多不同的情况,并且每种情况都可以 return 不同的视图类型,这确实是一项艰巨的任务。我建议对这段代码进行一些小的重构。正如我们所看到的,只有两个参数取决于计算。所以:

  1. 让我们创建一个结构来存储这些参数
private struct ContentParameters {
    var backgroundColor: Color
    var offsetY: CGFloat
}
  1. 让我们将所有计算移动到一个单独的方法中,该方法return是一个结果(在我们的例子中变量也有效):
private var contentParameters: ContentParameters {
    if (self.position == CardPosition.bottom(UIScreen.main.bounds.height - (77.5)) || self.position == CardPosition.middle(UIScreen.main.bounds.height - (135))) && mapStyle == MGLStyle.outdoorsStyleURL {
        return ContentParameters(
            backgroundColor: .white,
            offsetY: self.position.offset + self.dragState.translation.height - keyboardResponder.currentHeight
        )
    } else if self.position == CardPosition.bottom(UIScreen.main.bounds.height - (77.5)) || self.position == CardPosition.middle(UIScreen.main.bounds.height - (135)) && mapStyle == MGLStyle.darkStyleURL {
        return ContentParameters(
            backgroundColor: Color(red: 15/255, green: 15/255, blue: 15/255),
            offsetY: self.position.offset + self.dragState.translation.height - keyboardResponder.currentHeight
        )
    } else if mapStyle == MGLStyle.darkStyleURL {
        return ContentParameters(
            backgroundColor: Color(red: 15/255, green: 15/255, blue: 15/255),
            offsetY: self.position.offset + self.dragState.translation.height
        )
    } else {
        return ContentParameters(
            backgroundColor: .white,
            offsetY: self.position.offset + self.dragState.translation.height
        )
    }
}

现在,由于我们已经移除了所有复杂的计算,让我们使用它稍微清理一下代码:

var body: some View {
    let drag = DragGesture()        // this part stays the same
        .updating($dragState) { drag, state, transaction in
            state = .dragging(translation: drag.translation)
        }.onEnded(onDragEnded)
        
    let parameters = contentParameters // storing in a constant to not to calculate multiple times
        
    return VStack (spacing: 0) {       // using the real content from the original code
        Handle(mapStyle: mapStyle)
        content()
    }
    // Applying all the modifiers from the original code
    .frame(height: UIScreen.main.bounds.height)
    .background(parameters.backgroundColor)    // using background color that was already calculated
    .cornerRadius(10.0)
    .shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
    .offset(y: parameters.offsetY)             // using the offset that was alredy calcualted
    .animation(self.dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
    .gesture(drag)
}

我相信这会解决问题——生成的代码对于编译器来说更容易理解。作为一个额外的好处,我们获得了更多 SwiftUI 动画友好代码(以防您以后决定添加动画支持)。