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