Why the preview of my program displays different from the one displayed in the simulator?
Forgive me about my english, because I am not a native english language speaker.
Things are like this, I wrote a program when I was following CS193p. Everything seemed OK in the preview, but when I pressed the button "Command + R" to run it in a simulator.
Maybe there are some "Static Misused" in my code, so I posted all of my swift files.
I really want to know the reason for the error, thank you for your answer.
This is the main file.
//
// assignment_2App.swift
// assignment_2
//
// Created by Tao Feng on 2022/4/16.
//
import SwiftUI
@main
struct assignment_2App: App {
var body: some Scene {
let game = EmojiMemoryGame(theme1: "Vehicle", pairsShowed: 4)
// The previews actually show 4 pairs of cards which is what I need it to be
WindowGroup {
ContentView(viewModel: game)
}
}
}
This is previews part of the contentView file
//
// ContentView.swift
// assignment_2
//
// Created by Tao Feng on 2022/4/16.
//
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel: EmojiMemoryGame
var body: some View {
VStack {
Text("Memorized!")
.font(.largeTitle)
.padding(.bottom)
HStack {
Text("Theme: \(viewModel.themeShow.name)")
.foregroundColor(viewModel.themeShow.color)
Spacer()
Text("Scores: \(viewModel.scoreShow)")
}.padding()
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 100))]) {
ForEach(viewModel.cards) {
card in CardView(card: card).aspectRatio(2/3, contentMode: .fit)
.onTapGesture {
viewModel.choose(card)
}
}
}
}
.foregroundColor(viewModel.themeShow.color)
.padding(.horizontal)
Button {
viewModel.newGame()
} label: {
Text("New Game")
}
}
}
}
struct CardView: View {
var card: MemoryGame<String>.Card
var body: some View {
ZStack {
let shape = RoundedRectangle(cornerRadius: 30)
if card.isFaceUp {
shape.fill(.white)
shape.strokeBorder(lineWidth: 5)
Text(card.content).font(.largeTitle)
} else if card.isMatched {
shape.opacity(0)
}
else {
shape.fill()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let game = EmojiMemoryGame(theme1: "Vehicle", pairsShowed: 4)
// The previews actually show 4 pairs of cards which is what I need it to be
ContentView(viewModel: game)
}
}
This is the viewModel of my program
//
// EmojiMemoryGame.swift
// assignment_2
//
// Created by Tao Feng on 2022/4/16.
//
import Foundation
class EmojiMemoryGame: ObservableObject {
static var themes: Array<Theme> = [
Theme(
name: "Vehicle",
emojis: ["π", "π", "π", "π", "π",
"π", "π", "π", "π", "π",
"π»", "π", "π", "π", "π¦―",
"π¦½", "π¦Ό", "π©Ό", "π΄", "π²"],
color: .blue,
pairs: 20
// The simulator actually shows 20 pairs of cards which I felt confused
),
Theme(
name: "Fruit",
emojis: ["π", "π", "π", "π", "π",
"π", "π", "π", "π", "π«",
"π", "π", "π" ,"π₯", "π"],
color: .green,
pairs: 15
),
Theme(
name: "Sport",
emojis: ["β½οΈ", "π", "π", "βΎοΈ", "π₯",
"πΎ", "π", "π", "π₯", "π±",
"πͺ", "π", "πΈ", "π", "π",
"π₯", "π", "πͺ"],
color: .orange,
pairs: 18
)
]
static var themePick: Theme = themes[0]
init(theme1: String, pairsShowed: Int) {
for index in EmojiMemoryGame.themes.indices {
if theme1 == EmojiMemoryGame.themes[index].name {
EmojiMemoryGame.themePick = EmojiMemoryGame.themes[index]
EmojiMemoryGame.themePick.pairs = pairsShowed
}
}
}
static func startGame(theme: Theme) -> MemoryGame<String> {
MemoryGame<String>(pairsOfCards: theme.pairs) {
index in theme.emojis[index]
}
}
var themeShow: Theme {
return EmojiMemoryGame.themePick
}
@Published private var model: MemoryGame<String> = startGame(theme: themePick)
var cards: Array<MemoryGame<String>.Card> {
return model.cards
}
var scoreShow: Int {
return model.scores
}
// MARK: - Intent(s)
func choose(_ card: MemoryGame<String>.Card) {
// card.isFaceUp.toggle()
// objectWillChange.send()
model.choose(card)
}
func newGame() {
EmojiMemoryGame.themePick = EmojiMemoryGame.themes.randomElement()!
EmojiMemoryGame.themePick.emojis.shuffle()
model = EmojiMemoryGame.startGame(theme: EmojiMemoryGame.themePick)
}
}
And this is the Model part of my program
//
// MemoryGame.swift
// assignment_2
//
// Created by Tao Feng on 2022/4/16.
//
import Foundation
struct MemoryGame<CardContent> where CardContent: Equatable{
var cards: Array<Card>
private(set) var scores: Int = 0
private var indexOfTheOneAndOnlyOne: Int?
mutating func choose(_ card: Card) {
if let chosenIndex = index(of: card), !cards[chosenIndex].isFaceUp, !cards[chosenIndex].isMatched {
if let indexOfExistingOne = indexOfTheOneAndOnlyOne {
if cards[indexOfExistingOne].content == cards[chosenIndex].content {
cards[indexOfExistingOne].isMatched = true
cards[chosenIndex].isMatched = true
scores += 2
}
else {
if cards[chosenIndex].hasBeenShowed {
scores -= 1
}
if cards[indexOfExistingOne].hasBeenShowed {
scores -= 1
}
cards[chosenIndex].hasBeenShowed = true
cards[indexOfExistingOne].hasBeenShowed = true
}
indexOfTheOneAndOnlyOne = nil
}
else {
for index in cards.indices {
cards[index].isFaceUp = false
}
indexOfTheOneAndOnlyOne = chosenIndex
}
cards[chosenIndex].isFaceUp.toggle()
}
print("\(cards)")
}
func index(of card: Card) -> Int? {
for i in 0..<cards.count {
if card.id == cards[i].id {
return i
}
}
return nil
}
struct Card: Identifiable {
let id: Int
let content: CardContent
var isFaceUp: Bool = false
var isMatched: Bool = false
var hasBeenShowed = false
}
init(pairsOfCards: Int, contentGenerator: (Int) -> CardContent) {
cards = Array<Card>()
for index in 0..<pairsOfCards {
let contents = contentGenerator(index)
cards.append(Card(id: index*2, content: contents))
cards.append(Card(id: index*2+1, content: contents))
}
cards.shuffle()
}
}
And this is the Theme Model
//
// ThemePick.swift
// assignment_2
//
// Created by Tao Feng on 2022/4/16.
//
import Foundation
import SwiftUI
struct Theme {
var name: String
var emojis: Array<String>
var color: Color
var pairs: Int
init(name: String, emojis: Array<String>, color: Color, pairs: Int) {
self.name = name
self.emojis = emojis
self.color = color
self.pairs = pairs
}
}