首页 > 解决方案 > SwiftUI 编译器无法在合理的时间内进行类型检查

问题描述

我有一个 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 把它变成一个新的视图,并在这个视图中调用它。但要做到这一点,我需要将播放器传递到新视图中,该视图已经传递到该视图中。这是简化视图并消除此错误的正确方法吗?

标签: viewswiftuisimplify

解决方案


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

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

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由于case 和 else case之间的唯一区别是offset,我们可以在cardNumbercase 中使用零偏移量:

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)
    }
}

推荐阅读