I am unsure the correct way to model my data.
I have a swift data object and then some referenced objects. Is there ever a reason those should just be structs or should they always be swift data objects themselves?
for example right now this is what I'm doing:
@Model
final class Exam {
var timestamp: Date
@Attribute(.unique) var examID: UUID
var title: String
var questions: [Question]
...
}
and Question
is
struct Question: Codable, Identifiable {
var id: UUID
var number: Int
var points: Int
var prompt: String
var answer: String
}
is there any problem with this or should I not be using a Struct for Question and instead use another Swift Data object with @Relationship
?
I thought since its a simple object just using a struct would be fine, however...
when I create a new Question object, it seems to create SwiftUI retain cycles with the warning
=== AttributeGraph: cycle detected through attribute 633984 ===
in the terminal
for example,
Button("Add Question", systemImage: "questionmark.diamond") {
let newQuestion = Question(id: UUID(), number: exam.questions.count+1, points: 1, prompt: "", answer: "", type: .multipleChoice)
exam.questions.append(newQuestion)
}
So, is it ok to mix structs with swift data objects or is it not best practice? And is this causing the SwiftUI retain cycles or are the issues unrelated?
I think your question should be a class if you want to persist it in SwiftData. I think the general advice (for SwiftData) is: structs are for views, classes are for models.
Your models would be something like this:
@Model
final class Exam {
let timestamp: Date
let id: String
var title: String
@Relationship(deleteRule: .cascade, inverse: \Question.exam) var questions: [Question] = []
init(title:String = "") {
self.timestamp = .now
self.id = UUID().uuidString
self.title = title
}
}
@Model
final class Question {
let id: String
var number: Int
var points: Int
var prompt: String
var answer: String
@Relationship var exam: Exam? = nil
init(
number: Int = 0,
points: Int = 0,
prompt: String = "",
answer: String = ""
) {
self.id = UUID().uuidString
self.number = number
self.points = points
self.prompt = prompt
self.answer = answer
}
}
I hope this helps!