【问题标题】:SwiftUI Compiler unable to type-check in reasonable timeSwiftUI 编译器无法在合理的时间内进行类型检查
【发布时间】:2021-08-23 21:55:52
【问题描述】:

我有一个 playerView 视图,它当前显示两件事:玩家的手牌和他们牌的总价值。它是这样定义的:

struct playerView: View{
        @ObservedObject var player:Player
        var isDealt:Bool
        
        var body: some View{
            VStack{
                ZStack{
                    ForEach(player.viewCards.indices, id: \.self){ cardNumber in
                        //The first card has no offset so need conditional
                        if cardNumber == 0{
                            if player.viewCards[cardNumber]{
                                Image(player.hand[cardNumber].suit.rawValue + String(player.hand[cardNumber].rank) ).resizable().frame(width:120, height:160)
                            }
                        }   else{
                            if player.viewCards[cardNumber]{
                                Image(player.hand[cardNumber].suit.rawValue + String(player.hand[cardNumber].rank) ).resizable().frame(width:120, height:160).offset(x: 40, y: -40)
                            }
                        }
                    }
                }.padding(.top, 140)
                
                //Display player card Score
                if isDealt{
                    if player.hasAce{
                        Text("Card Score\n" + String(player.cardScore) + " / " + String(player.cardScore + 10)).font(.body).bold().foregroundColor(.white).lineLimit(2).multilineTextAlignment(.center)
                    }   else{
                        Text("Card Score\n" + String(player.cardScore)).font(.body).bold().foregroundColor(.white).lineLimit(2).multilineTextAlignment(.center)
                    }
                }
            }
        }
    }

每当我尝试向代码中添加几乎任何内容时,我都会不断收到错误消息“编译器无法在合理的时间内对该表达式进行类型检查;尝试将表达式分解为不同的子表达式”。例如,如果我尝试将 ForEach 循环的 else 部分中 Image 的偏移量更改为 (x: 40 * cardNumber, y: -40 * cardNumber),我会收到错误消息。我认为要解决这个问题,我需要通过创建另一个视图来进一步简化我的代码,以便在该视图中使用。但我不完全确定如何/为什么,因为这种观点对我来说似乎并不复杂。有人可以举个例子说明我应该做些什么来进一步简化它吗?

我对我应该做的事情的理解是获取代码块并将它们转换为视图。所以拿 ZStack 把它变成一个新的视图,并在这个视图中调用它。但要做到这一点,我需要将播放器传递到新视图中,该视图已经传递到该视图中。这是简化视图并消除此错误的正确方法吗?

【问题讨论】:

  • 你也可以尝试把它分解成几个计算变量,比如 body. var row : some View{ ... 代码在这里}
  • 如果您得到“编译器无法在合理的时间内对该表达式进行类型检查;请尝试将表达式分解为不同的子表达式”,在许多情况下您的代码肯定有问题。
  • 包括minimal reproducible example。否则,即使不是不可能,也很难提出解决方案。
  • 这个表达式player.viewCards[cardNumber]是否返回一个布尔值(真/假)?

标签: view swiftui simplify


【解决方案1】:

我们可以做一些事情来帮助编译器。

对于卡片分数文本,您使用的是字符串连接,其中插值会更惯用。试试这个:

Text("""
    Card Score
    \(player.cardScore) / \(player.cardScore + 10)
    """
)

我们还可以将您的两个卡片分数分支合二为一:

let aceAlt = player.hasAce ? " / \(player.cardScore + 10)" : ""
Text("""
        Card Score
        \(player.cardScore)\(aceAlt)
        """
)
    .font(.body)
    .bold()
    .foregroundColor(.white)
    .lineLimit(2)
    .multilineTextAlignment(.center)

将图像名称计算提取到单独的属性中是合理的:

extension Card {
    fileprivate var imageName: String { "\(suit.rawValue)\(rank)" }
}

然后我们可以像这样创建Image

Image(player.hand[cardNumber].imageName)

由于cardNumber == 0 情况和else 情况之间的唯一区别是offset,我们可以在cardNumber 情况下使用零偏移:

Image(player.hand[cardNumber].imageName)
    .resizable()
    .frame(width:120, height:160)
    .offset(x: cardNumber == 0 ? 0 : 40, y: cardNumber == 0 ? 0 : -40)

如果您仍然遇到问题,请将卡片图像和卡片分数提取到辅助函数:

extension Card {
    fileprivate var imageName: String { "\(suit.rawValue)\(rank)" }
}

struct PlayerView: View {
    @ObservedObject var player: Player
    var isDealt: Bool

    var body: some View {
        VStack {
            ZStack {
                ForEach(player.viewCards.indices, id: \.self) { cardNumber in
                    if player.viewCards[cardNumber] {
                        cardImage(for: player.hand[cardNumber], isFirst: cardNumber == 0)
                    }
                }
            }
            .padding(.top, 140)

            if isDealt {
                cardScoreView
            }
        }
    }

    private func cardImage(for card: Card, isFirst: Bool) -> some View {
        return Image(card.imageName)
            .resizable()
            .frame(width: 120, height: 160)
            .offset(
                x: isFirst ? 0 : 40,
                y: isFirst ? 0 : -40)

    }

    private var cardScoreView: some View {
        let aceAlt = player.hasAce ? " / \(player.cardScore + 10)" : ""
        return Text("""
            Card Score
            \(player.cardScore)\(aceAlt)
            """
        )
            .font(.body)
            .bold()
            .foregroundColor(.white)
            .lineLimit(2)
            .multilineTextAlignment(.center)
    }
}

【讨论】:

    【解决方案2】:

    假设“player.viewCards[cardNumber]”返回一个布尔值,您可以尝试重新构建您的 if,如下所示:

            if player.viewCards[cardNumber] {
                if cardNumber == 0 {
                    Image(player.hand[cardNumber].suit + String(player.hand[cardNumber].rank) ).resizable().frame(width:120, height:160)
                } else {
                    Image(player.hand[cardNumber].suit + String(player.hand[cardNumber].rank) ).resizable().frame(width:120, height:160).offset(x: 40, y: -40)
                }
            } else {
                EmptyView()
            }
    

    【讨论】:

      猜你喜欢
      • 2021-10-26
      • 2020-06-30
      • 2020-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多