簡體   English   中英

SwiftUI 不更新子視圖中的 ObservedObject

[英]SwiftUI not updating ObservedObject in child-view

所以我嘗試從斯坦福 CS193p 學習 SwiftUI。 這很好用,但是,我無法理解為什么這不起作用。 我和老師的觀點完全一樣:

struct ContentView: View {

    @ObservedObject var viewModel: EmojiMemoryGame

    var body: some View {
        HStack {
            ForEach(self.viewModel.cards) { card in
                CardView(card: card).onTapGesture {
                    self.viewModel.chooseCard(card: card)
                }
            }
            .aspectRatio(2/3, contentMode: .fit)
        }
            .foregroundColor(.orange)
            .padding()
            .font(viewModel.numberOfPairsOfCards >= 5 ? .callout : .largeTitle)
    }
}

struct CardView: View {

    var card: MemoryGame<String>.Card

    var body: some View {
        VStack {
            ZStack {
                if card.isFaceUp {
                    RoundedRectangle(cornerRadius: 10.0).fill(Color.white)
                    RoundedRectangle(cornerRadius: 10.0).stroke(lineWidth: 3)
                    Text(card.content)
                } else {
                    RoundedRectangle(cornerRadius: 10.0).fill(Color.orange)
                }
            }
        }
    }
}

問題是這不會更新視圖,就好像來自 model 的已發布信息沒有傳遞到層次結構中一樣。 我知道它有效,因為如果我將代碼更改為:

struct ContentView: View {

    @ObservedObject var viewModel: EmojiMemoryGame

    var body: some View {
        HStack {
            ForEach(self.viewModel.cards) { card in
                ZStack {
                    if card.isFaceUp {
                        RoundedRectangle(cornerRadius: 10.0).fill(Color.white)
                        RoundedRectangle(cornerRadius: 10.0).stroke(lineWidth: 3)
                        Text(card.content)
                    } else {
                        RoundedRectangle(cornerRadius: 10.0).fill(Color.orange)
                    }
                }
                    .onTapGesture {
                        self.viewModel.chooseCard(card: card)
                    }
            }
            .aspectRatio(2/3, contentMode: .fit)
        }
            .foregroundColor(.orange)
            .padding()
            .font(viewModel.numberOfPairsOfCards >= 5 ? .callout : .largeTitle)
    }
}

一切正常。 非常感謝所有幫助!

class EmojiMemoryGame: ObservableObject {

    @Published private var game: MemoryGame<String> = EmojiMemoryGame.createMemoryGame()

    static private func createMemoryGame() -> MemoryGame<String> {
        let emojis = ["🎃", "👻", "🕷", "😈", "🦇"]
        return MemoryGame(numberOfPairsOfCards: Int.random(in: 2...5)) { emojis[$0] }
    }

    //MARK: - Access to the Model
    var cards: Array<MemoryGame<String>.Card> {
        game.cards
    }

    var numberOfPairsOfCards: Int {
        game.cards.count / 2
    }

    //MARK: - Intents

    func chooseCard(card: MemoryGame<String>.Card) {
        game.choose(card)
    }
}

struct MemoryGame<CardContent> {
    var cards: Array<Card>

    mutating func choose(_ card: Card) {
        if let indexOfCard = cards.firstIndex(of: card) {
            cards[indexOfCard].isFaceUp.toggle()
        }
    }

    init(numberOfPairsOfCards: Int, cardContentFactory: (Int) -> CardContent) {
        cards = Array<Card>()
        for pairIndex in 0..<numberOfPairsOfCards {
            let content = cardContentFactory(pairIndex);
            cards.append(Card(content: content, id: pairIndex * 2))
            cards.append(Card(content: content, id: pairIndex * 2 + 1))
        }
        cards.shuffle()
    }

    struct Card: Identifiable, Equatable {

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

        var isFaceUp = true
        var isMatched = false
        var content: CardContent
        var id: Int

    }
}

Card 結構中相等運算符的實現僅比較 id。 CardView 沒有更新,因為 SwiftUI 推斷卡沒有改變。

請注意,您可能還想檢查 card 的其他屬性(CardContent 需要符合 Equatable)。

struct Card: Identifiable, Equatable {

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

        var isFaceUp = true
        var isMatched = false
        var content: CardContent
        var id: Int

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM