GO FURTHER, FASTER: Try the Swift Career Accelerator today! >>

SOLVED: A weird problem, about swiftData insert

Forums > SwiftUI

I've got a Classification model. And a TodoItem model , which has a attribute type Classification


@Model
final class Classification: Identifiable, Equatable {
    var id: UUID
    var image: String
    var background: Int
    var name: String

    init(id: UUID = UUID(), image: String, background: Int, name: String) {
        self.id = id
        self.image = image
        self.background = background
        self.name = name
    }

    static let mockData = Classification(image: "questionmark", background: 0xFF0000, name: "tag")
}
@Model
final class TodoItem: Identifiable {
    var id: UUID
    var title: String
    var startTime: Date
    var endTime: Date
    var isCompleted: Bool
    var isLog: Bool
    var classification: Classification?

    init(id: UUID = UUID(),  title: String, startTime: Date, endTime: Date, isCompleted: Bool, isLog: Bool, classification: Classification?) {
        self.id = id
        self.title = title
        self.startTime = startTime
        self.endTime = endTime
        self.isCompleted = isCompleted
        self.isLog = isLog
        self.classification = classification
    }

    convenience init(title: String, startTime: Date, endTime: Date, classification: Classification?) {
        self.init(id: UUID(), title: title, startTime: startTime, endTime: endTime, isCompleted: true, isLog: true, classification: classification)
    }

    static let mockDataTodo = TodoItem( title: "todo", startTime: Date(), endTime: Date(timeIntervalSinceNow: 3000), isCompleted: false, isLog: false, classification: nil)
    static let mockDataLog = TodoItem(title: "log", startTime: Date(timeIntervalSinceNow: -3000), endTime: Date(), classification: nil)
}

on my view ,when i create a todoItem , I need to choose classifications which stored in swiftData through a Picker

 @Query private var classifications: [Classification]
 @State private var todoItem: TodoItem

Picker("choose tag", selection: $selectedClassification) {
                Text("empty").tag(nil as Classification?)
                ForEach(classifications) { item in
                    TagView(classification: item)
                    .tag(Optional(item))
                }
            }
            .onChange(of: selectedClassification) { oldVlaue, newValue in
                if let newValue {
                    todoItem.classification = newValue
                } else {
                    todoItem.classification = nil
                }
            }

            CircleButton(imageString: "checkmark", width: 35, backgroundColor: .green, imageColor: .white,  ifGradient: true)
                    .onTapGesture {
                        withAnimation(.snappy) {
                            modelContext.insert(todoItem)
                            dismiss()
                        }
                    }

I got a CircleButton to execute modelContext.insert, but When I just picked classification, this todoItem will be stored immediately! I have no idea about this. But if I do not get classifications from swiftdata, but define a mock classifications myself, it will not be automatically inserted.

//    @Query private var classifications: [Classification]
    var classifications: [Classification] = [
        Classification(image: "checkmark", background: 0xff12df, name: "1"),
        Classification(image: "checkmark", background: 0xff12df, name: "2"),
        Classification(image: "checkmark", background: 0xff12df, name: "3"),
    ]

2      

Several things to note.

  • @Model classes conform to Persistent Model protocol, which in turn make your model: Observable and Identifiable so you don't really need to make it Identifiable explicitly.
  • By default when you attach your ModelContainer it has autosave flag as On, meaning whatever changes you make will be saved automatically almost immediately. So when you change your Classification from nil to some value in todoItem that has been already created, it will be saved immediately as it has relationship set and it knows which context is used for that todoItem. You can switch autosave to Off in ModelContainer setup, but once it is off it is your responsibility to add modelContext.save() every time you introduce any changes to data.
  • When you define your classifications yourself in the array, you don't add it to modelContext, so without modelContext.insert(Classification(image: "checkmark", background: 0xff12df, name: "3")). Context has no clue that you added something so it will not update anything.

Hope this will help.

3      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure and A/B test your entire paywall UI without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.