SwiftUI没有更新子视图中的ObservedObject。

问题描述 投票:0回答:1

于是我试着从斯坦福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)
                }
            }
        }
    }
}

问题是这并没有更新视图 就好像模型中的发布信息没有被传递到下层一样 我知道它的工作原理,因为如果我把代码改成这样。

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

    }
}

swift swiftui
1个回答
1
投票

你的Card结构中的平等运算符的实现只比较id。因为SwiftUI推断卡片没有变化,所以CardView没有更新。

注意,你可能要检查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

    }
© www.soinside.com 2019 - 2024. All rights reserved.