当我在更新观察到的对象时遇到了一些问题,我跟随了this lecture.我有一个@ObservedObject,叫做EmojiMemoryGame,有一个MemoryGame<String>变量,叫做model."MemoryGame是一个存储一系列卡片的 struct ,每个卡片都有一个Bool变量,用于存储卡片是否正面朝上.

My ContentView是一个在屏幕上显示网格中每张卡的视图.当用户点击卡时,viewModel.choose(card)切换卡的isFaceUp变量;问题是,这不会导致卡在屏幕上翻转.这是我在ContentView.swift中的代码:

struct ContentView: View {
    @ObservedObject var viewModel: EmojiMemoryGame
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: [GridItem(.adaptive(minimum: 89))]) {
                ForEach(viewModel.cards) { card in
                    CardView(card: card)
                        .aspectRatio(2/3, contentMode: .fit)
                        .onTapGesture {
                            viewModel.choose(card)
                        }
                }
            }
        }
        .foregroundColor(.red)
        .padding(.horizontal)
    }
}

struct CardView: View {
    let card: MemoryGame<String>.Card
    
    var body: some View {
        ZStack {
            let shape = RoundedRectangle(cornerRadius: 20)
            
            if card.isFaceUp {
                shape
                    .fill()
                    .foregroundColor(.white)
                shape
                    .strokeBorder(lineWidth: 3)
                Text(card.content)
                    .font(.largeTitle)
            } else {
                shape
                    .fill()
            }
        }
    }
}

然而,如果我只是将CardView中的代码直接复制/粘贴到ContentView的主体中(见下文),那么代码就会像预期的那样工作,因此我不确定这里到底发生了什么.

struct ContentView: View {
    @ObservedObject var viewModel: EmojiMemoryGame
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: [GridItem(.adaptive(minimum: 89))]) {
                ForEach(viewModel.cards) { card in
                    ZStack {
                        let shape = RoundedRectangle(cornerRadius: 20)
                        
                        if card.isFaceUp {
                            shape
                                .fill()
                                .foregroundColor(.white)
                            shape
                                .strokeBorder(lineWidth: 3)
                            Text(card.content)
                                .font(.largeTitle)
                        } else {
                            shape
                                .fill()
                        }
                    }
                    .aspectRatio(2/3, contentMode: .fit)
                    .onTapGesture {
                        viewModel.choose(card)
                    }
                }
            }
        }
        .foregroundColor(.red)
        .padding(.horizontal)
    }
}

编辑:这是我的EmojiMemoryGame.swift:

class EmojiMemoryGame: ObservableObject {
    static let emojis = ["????", "????", "????‍????️", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????‍????", "????", "????", "????", "????"]
    
    static func createMemoryGame() -> MemoryGame<String> {
        MemoryGame<String>(numberOfPairsOfCards: 4) { pairIndex in
            emojis[pairIndex]
        }
    }

    @Published var model: MemoryGame<String> = createMemoryGame()

    var cards: Array<MemoryGame<String>.Card> {
        return model.cards
    }
    
    func choose(_ card: MemoryGame<String>.Card) {
        model.choose(card)
    }
}

MemoryGame.swift:

struct MemoryGame<CardContent> where CardContent: Equatable {
    
    struct Card: Identifiable, Equatable {
        var isFaceUp: Bool = false
        var isMatched: Bool = false
        var content: CardContent
        
        var id: Int
        
        static func == (lhs: MemoryGame<CardContent>.Card, rhs: MemoryGame<CardContent>.Card) -> Bool {
            lhs.id == rhs.id
        }
        
    }
    
    private(set) var cards: Array<Card>
        
    init(numberOfPairsOfCards: Int, createCardContent: (Int) -> CardContent) {
        cards = Array<Card>()
        // add numberOfPairsOfCards * 2 cards to cards array
        for pairIndex in 0..<numberOfPairsOfCards {
            let content: CardContent = createCardContent(pairIndex)
            cards.append(Card(content: content, id: pairIndex*2))
            cards.append(Card(content: content, id: pairIndex*2 + 1))
        }
    }
    
    mutating func choose(_ card: Card) {
        let chosenIndex = cards.firstIndex(of: card)
        cards[chosenIndex!].isFaceUp.toggle()
    }
    
}

推荐答案

ForEach没有检测到任何卡的变化,因为它使用Equatable,在您的情况下,它只使用id.

以下是修复方法:

struct Card: Identifiable, Equatable {
    var isFaceUp: Bool = false
    var isMatched: Bool = false
    var content: CardContent

    var id: Int

    static func == (lhs: MemoryGame<CardContent>.Card, rhs: MemoryGame<CardContent>.Card) -> Bool {
        lhs.id == rhs.id && lhs.isFaceUp == rhs.isFaceUp   // << here !!
    }
}

还需要更新

mutating func choose(_ card: Card) {
    let chosenIndex = cards.firstIndex{ $0.id == card.id } // << here !!
    cards[chosenIndex!].isFaceUp.toggle()
}

使用Xcode 13.4/iOS 15.5测试

Swift相关问答推荐

在列表项内的NavigationLink中的按钮无法正常工作

SwiftData查询按日期排序的项的属性数组

RealityKit(VisionOS)中的PhysicBodyComponent和DragGesture

SwiftData:线程1:&Quot;NSFetchRequest找不到实体名称';提醒&q;的NSEntityDescription

依赖于@Environment的init@StateObject

如何在visionOS中进行购买?&# 39;购买(选项:)在visionOS中不可用

SwiftUI轨迹绘制怪异

Swift-Can无法在AudioKit中找出简单的麦克风效果-文件链

如何在AudioKit中实现自定义音效 node ?

在SwiftUI中判断选项时避免重复查看

memcpy 复制带偏移量的数组

NavigationStack 和 TabView - 工具栏和标题不显示

iOS16 Bug 键盘在表单解雇 SwiftUI 时打破布局

Swift 中的Combine和didSet有什么区别?

SwiftUI:当先前的视图列表更改时,NavigationView 详细视图会弹出回栈

在 RealityKit 中创建转场

如何获取 NSRunningApplication 的参数?

找不到目标AAA的 SPM 工件 - 仅限 Xcode 13.3

如何在 iOS Swift 中进行多线程、并发或并行?

用 UIBezierPath 画一条线