I am a new coder. I am trying to program a feature in a game so that if it is the first time the user has logged into the app, the user will be presented with a tutorial; however, it doesn't seem to save.
It does change, but it just doesn't save.
@main
struct Fixing_The_Tutorial_And_IntroApp: App {
@StateObject var gameData = ResourcePool()
@State var returnedData = ResourcePoolData()
var body: some Scene {
WindowGroup {
ContentView(gameData: gameData)
.onAppear{
returnedData = load(key: key) ?? ResourcePoolData()
gameData.setValue(resourcePoolData: returnedData)
}
}
}
}
struct ContentView: View { @ObservedObject var gameData: ResourcePool
@ObservedObject var gameCon : GameCondition = GameCondition.shared
var body: some View {
VStack {
Button("I've seen it"){
gameData.setSeen()
}
if !gameCon.checkViewedTutorial() {
Rectangle().frame(width: 100, height: 100)
}
}
.padding()
}
}
func save<T: Identifiable & Codable>(items: T, key: String) {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(items) {
let defaults = UserDefaults.standard
defaults.set(encoded, forKey: key)
print("Saving \(key)")
}
}
func load<T: Identifiable & Codable>(key: String) -> T? {
guard let data = UserDefaults.standard.object(forKey: key) as? Data else { return nil }
let decoder = JSONDecoder()
if let dataArray = try? decoder.decode(T.self, from: data) {
print("Loading \(key)")
return dataArray
}
return nil
}
struct ResourcePoolData : Codable & Identifiable {
var id = UUID()
var gameConData : GameConditionModel
init(resourcePool : ResourcePool){
self.gameConData = resourcePool.gameConData
}
init(){
gameConData = GameConditionModel()
}
}
class GameCondition : ObservableObject {
@Published var data : GameConditionModel
static let shared = GameCondition(data: GameConditionModel())
private init(data: GameConditionModel) {
self.data = data
}
func checkViewedTutorial()-> Bool {
return data.hasViewedTutorial
}
func reset(){
data.reset()
}
}
struct GameConditionModel : Identifiable, Codable {
var id = UUID()
var hasViewedTutorial = false
mutating func reset(){
hasViewedTutorial = false
}
}
let key = "game data"
class ResourcePool : ObservableObject {
@Published var gameConData : GameConditionModel = GameConditionModel()
@Published var gameCon : GameCondition = GameCondition.shared
func setValue(resourcePoolData: ResourcePoolData) {
self.gameConData = resourcePoolData.gameConData
}
func reset() {
GameCondition.shared.reset()
}
func setSeen(){
gameCon.data.hasViewedTutorial = true
save(items: ResourcePoolData(resourcePool: self), key: key)
//print("hasViewedTutorial: \(gameCon.data.hasViewedTutorial)")
//Loading game data
//Saving game data
//hasViewedTutorial: true
}
}
I've simplified the code to the only moving parts. I've thrown it into Bing, but this is what it gives me.
The code you provided seems to be missing the
save
function call in thesetSeen
method of theResourcePool
class. This means that thehasViewedTutorial
property is not being saved toUserDefaults
when the button is pressed. You can fix this by adding the following line to thesetSeen
method:
save(items: ResourcePoolData(resourcePool: self), key: key)
This will save the current state of the
ResourcePoolData
object toUserDefaults
using the providedkey
. Once this change is made, pressing the button should save the value ofhasViewedTutorial
toUserDefaults
. Let me know if this helps!
But that simply, is not true.
I've also made sure to check whether the thing was being saved in
func setSeen(){
gameCon.data.hasViewedTutorial = true
save(items: ResourcePoolData(resourcePool: self), key: key)
print("hasViewedTutorial: \(gameCon.data.hasViewedTutorial)")
}
And this was what I got
Loading game data, Saving game data, hasViewedTutorial: true
So I'm a bit at a loss. I don't see anything that can be going wrong.