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 不同的视图类型,这确实是一项艰巨的任务。我建议对这段代码进行一些小的重构。正如我们所看到的,只有两个参数取决于计算。所以:
- 让我们创建一个结构来存储这些参数
private struct ContentParameters {
var backgroundColor: Color
var offsetY: CGFloat
}
- 让我们将所有计算移动到一个单独的方法中,该方法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 动画友好代码(以防您以后决定添加动画支持)。