UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: SwiftData and deleting a Double Linked List

Forums > SwiftUI

Anyone know how SwiftData handles deletion of a Double Linked List? the problem I have is understanding the implied relationships and deletions when I delete a sidebar [modelContext.delete(sidebar)]. Sidebar should have a relationship to the head of the list, which then has a relationship to the next in the list, etc. Since I am not defining a "Cascade" then I don't know what happens.

I have:

@Model
public final class Sidebar: Hashable, Codable, ObservableObject  {

// bunch of stuff

    var paragraph_: Paragraph?

then:

@Model
public class Paragraph: Hashable, Codable {

    public var id: String

    var sidebar: Sidebar?
    var previous_: Paragraph?
    var next_: Paragraph?
    var attrStringData_: Data?

3      

Hi,

Based on the testing i've done if you delete the sidebar it will not delete the head or the body of the linked list but if you use .Cascade it will delete the sidebar and the head but not the body, you can try it with the code below.

@Model
public final class Sidebar  {

    public var id: String?

    // bunch of stuff

    @Relationship(deleteRule: .cascade)
    var paragraph_: Paragraph?

    @Transient 
    public var last: Paragraph? {
        guard var paragraph = paragraph_ else {
          return nil
        }

        while let next = paragraph.next_ {
            paragraph = next
        }
        return paragraph
    }

    @Transient 
    public func append(value: String) {
        let newParagraph = Paragraph(id: value)
        if let lastParagraph = last {
            newParagraph.previous_ = lastParagraph
            lastParagraph.next_ = newParagraph
        } else {
          paragraph_ = newParagraph
        }
    }

    init(paragraph_: Paragraph? = nil) {
        self.paragraph_ = paragraph_
    }
}

@Model
public class Paragraph {

    public var id: String?

    var sidebar: Sidebar?
    var previous_: Paragraph?
    var next_: Paragraph?
    var attrStringData_: Data?

    init(id: String? = nil, sidebar: Sidebar? = nil, previous_: Paragraph? = nil, next_: Paragraph? = nil, attrStringData_: Data? = nil) {
        self.id = id
        self.sidebar = sidebar
        self.previous_ = previous_
        self.next_ = next_
        self.attrStringData_ = attrStringData_
    }
}
struct ContentView: View {
    @Environment(\.modelContext) var modelContext

    @Query<Sidebar> var sidebars: [Sidebar]
    @Query(sort: \Paragraph.id) var paragraphs: [Paragraph]

    var body: some View {
        NavigationStack {
            List {
                Section("Sidebars") {
                    ForEach(sidebars) { sidebar in
                        Text(sidebar.id ?? "")
                    }
                    .onDelete(perform: { indexSet in
                        delete(indexSet)
                    })
                }
            }

            List {
                Section("Paragraphs") {
                    ForEach(paragraphs) { paragraph in
                        Text(paragraph.id ?? "")
                    }
                }
            }
            .toolbar(content: {
                ToolbarItem(placement: .topBarTrailing) {
                    Button("Add Sample") {
                        try? modelContext.delete(model: Sidebar.self)
                        try? modelContext.delete(model: Paragraph.self)

                        let sidebar = Sidebar()
                        sidebar.id = "Sidebar"
                        modelContext.insert(sidebar)

                        let head = Paragraph(id: "Head Paragraph")
                        head.sidebar = sidebar
                        sidebar.paragraph_ = head

                        for i in 0..<5 {
                            sidebar.append(value: "Paragraph Body \(i)")
                        }

                    }
                }
            })
        }
    }

    func delete(_ indexSet: IndexSet) {
        for index in indexSet {
            let sidebar = sidebars[index]
            modelContext.delete(sidebar)
        }
    }
}

4      

Thank you.

By making the links, Next/Prev, computed properties, I would expect the behavior you demostrate. However, in my code, I did not, instead these are links. So, they are in fact one-to-one links which the documentation says will be delieted if cascade is used. Implying it would follow the list.

I will do more testing. But, thank you, your code definitely works as expected.

3      

I'm not following, how are next and previous computed properties?, could you share some of your code? i'm very interested to see how you did it.

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 your entire paywall view 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.