Intro to problem:
I’m building a task manager app where users create custom quests, earn points, and redeem rewards. I’m using UserDefaults
to persist data. While rewards and points are saving and loading correctly, quests disappear when I leave the view. Debugging indicates encoding is successful, but decoding fails.
What I’ve tried:
• Ensured quest-saving logic is similar to working reward-saving logic.
• Used print statements to confirm encoding success and check saved data.
• Verified UserDefaults
contains saved quest data.
• Tried decoding but consistently receive an error.
My code:
import SwiftUI
class PointsManager: ObservableObject {
@Published var quests: [Quest] = []
init() {
loadQuests()
}
func addQuest(title: String, totalPoints: Int) {
let newQuest = Quest(title: title, totalPoints: totalPoints)
quests.append(newQuest)
saveQuests()
}
func saveQuests() {
do {
let encoded = try JSONEncoder().encode(quests)
UserDefaults.standard.set(encoded, forKey: "quests")
print("Encoding successful")
} catch {
print("Encoding failed: \(error.localizedDescription)")
}
}
func loadQuests() {
guard let savedData = UserDefaults.standard.data(forKey: "quests") else {
print("No data found")
return
}
do {
quests = try JSONDecoder().decode([Quest].self, from: savedData)
print("Decoding successful")
} catch {
print("Decoding failed: \(error.localizedDescription)")
}
}
}
struct Quest: Identifiable, Codable {
var id = UUID()
var title: String
var totalPoints: Int
}
Question:
Why is decoding failing while encoding succeeds? How can I correctly load and persist quests using UserDefaults
in SwiftUI?
Intro to problem:
I’m building a task manager app where users create custom quests, earn points, and redeem rewards. I’m using UserDefaults
to persist data. While rewards and points are saving and loading correctly, quests disappear when I leave the view. Debugging indicates encoding is successful, but decoding fails.
What I’ve tried:
• Ensured quest-saving logic is similar to working reward-saving logic.
• Used print statements to confirm encoding success and check saved data.
• Verified UserDefaults
contains saved quest data.
• Tried decoding but consistently receive an error.
My code:
import SwiftUI
class PointsManager: ObservableObject {
@Published var quests: [Quest] = []
init() {
loadQuests()
}
func addQuest(title: String, totalPoints: Int) {
let newQuest = Quest(title: title, totalPoints: totalPoints)
quests.append(newQuest)
saveQuests()
}
func saveQuests() {
do {
let encoded = try JSONEncoder().encode(quests)
UserDefaults.standard.set(encoded, forKey: "quests")
print("Encoding successful")
} catch {
print("Encoding failed: \(error.localizedDescription)")
}
}
func loadQuests() {
guard let savedData = UserDefaults.standard.data(forKey: "quests") else {
print("No data found")
return
}
do {
quests = try JSONDecoder().decode([Quest].self, from: savedData)
print("Decoding successful")
} catch {
print("Decoding failed: \(error.localizedDescription)")
}
}
}
struct Quest: Identifiable, Codable {
var id = UUID()
var title: String
var totalPoints: Int
}
Question:
Why is decoding failing while encoding succeeds? How can I correctly load and persist quests using UserDefaults
in SwiftUI?
- Hum..., I approved your Question, going first through the 'Staging Ground', but about "Tried decoding but consistently receive an error.", I think I probably fot to ask you to include that Error Msg, => if you can still add that to your Question...? (By editing it into the Question itself (in a Code or Quote Block), not as a Comment...) – chivracq Commented Mar 31 at 23:55
- 1 stackoverflow/questions/69148980/… – lorem ipsum Commented Apr 1 at 0:59
1 Answer
Reset to default -1Nothing wrong with the code you show. Here is my test code that shows storing and retrieving the data works.
Note, UserDefaults
is meant to be for small amount of data, not
really suited for an array of structs. Let me know if this example code does not work for you and show the full error you get.
class PointsManager: ObservableObject {
@Published var quests: [Quest] = []
init() {
loadQuests()
}
func addQuest(title: String, totalPoints: Int) {
let newQuest = Quest(title: title, totalPoints: totalPoints)
quests.append(newQuest)
saveQuests()
}
func saveQuests() {
do {
let encoded = try JSONEncoder().encode(quests)
UserDefaults.standard.set(encoded, forKey: "quests")
print("Encoding successful")
} catch {
print("Encoding failed: \(error.localizedDescription)")
}
}
func loadQuests() {
guard let savedData = UserDefaults.standard.data(forKey: "quests") else {
print("No data found")
return
}
do {
quests = try JSONDecoder().decode([Quest].self, from: savedData)
print("Decoding successful quests: \(quests)") // <--- here
} catch {
print("Decoding failed: \(error)")
}
}
}
struct Quest: Identifiable, Codable {
var id = UUID()
var title: String
var totalPoints: Int
}
struct ContentView: View {
@StateObject private var manager = PointsManager()
var body: some View {
VStack (spacing: 55) {
List(manager.quests) { quest in
HStack {
Text(quest.title)
Spacer()
Text("\(quest.totalPoints)")
}
}
Button("add Quest") {
let title = String(UUID().uuidString.prefix(10))
manager.addQuest(title: title, totalPoints: Int.random(in: 0...123))
}
Button("check Quest") {
print("---> quests: \(manager.quests)")
}
}
}
}