Skip to content

Instantly share code, notes, and snippets.

@verebes1
Last active March 6, 2024 19:47
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save verebes1/02950e46fff91456f2ad359b3f3ec3d9 to your computer and use it in GitHub Desktop.
Save verebes1/02950e46fff91456f2ad359b3f3ec3d9 to your computer and use it in GitHub Desktop.
Realm Cascade Deletion in Swift
import RealmSwift
import Realm
protocol CascadeDeleting {
func delete<S: Sequence>(_ objects: S, cascading: Bool) where S.Iterator.Element: Object
func delete<Entity: Object>(_ entity: Entity, cascading: Bool)
}
extension Realm: CascadeDeleting {
func delete<S: Sequence>(_ objects: S, cascading: Bool) where S.Iterator.Element: Object {
for obj in objects {
delete(obj, cascading: cascading)
}
}
func delete<Entity: Object>(_ entity: Entity, cascading: Bool) {
if cascading {
cascadeDelete(entity)
} else {
delete(entity)
}
}
}
private extension Realm {
private func cascadeDelete(_ entity: RLMObjectBase) {
guard let entity = entity as? Object else { return }
var toBeDeleted = Set<RLMObjectBase>()
toBeDeleted.insert(entity)
while !toBeDeleted.isEmpty {
guard let element = toBeDeleted.removeFirst() as? Object,
!element.isInvalidated else { continue }
resolve(element: element, toBeDeleted: &toBeDeleted)
}
}
private func resolve(element: Object, toBeDeleted: inout Set<RLMObjectBase>) {
element.objectSchema.properties.forEach {
guard let value = element.value(forKey: $0.name) else { return }
if let entity = value as? RLMObjectBase {
toBeDeleted.insert(entity)
} else if let list = value as? RLMSwiftCollectionBase {
for index in 0..<list._rlmCollection.count {
if let entity = list._rlmCollection.object(at: index) as? RLMObjectBase {
toBeDeleted.insert(entity)
}
}
}
}
delete(element)
}
}
@niralishaha25
Copy link

faced same problem. Looking for solution for "No type named 'ListBase' in module 'RealmSwift'".

@georgescumihai
Copy link

Probably won't fix all the situations, but you can solve some of the issue by using Embedded Objects.

Realm Uses Cascading Deletes for Embedded Objects
When you delete a Realm object, Realm automatically deletes any embedded objects referenced by that object. Any objects that your application must persist after the deletion of their parent object should use relationships instead.

@verebes1
Copy link
Author

I haven't used Realm for a while now. but I can point to the right place in Realm Docs
Two things come to my mind trying RealmSwift.List instead RealmSwift.ListBase
And cleaning your derived data folder from Xcode.
Again these are only some ideas to go forward. I haven't tried them.

@aleyooop
Copy link

aleyooop commented Jan 25, 2022

@jhoanarango @niralishaha25 as mentioned before, you can use Embedded Objects for automated cascade deleting. But if you still want to use the snippet on realm v10+, that should work as follows:

private func resolve(element: Object, toBeDeleted: inout Set<RLMObjectBase>) {
    element.objectSchema.properties.forEach {
        guard let value = element.value(forKey: $0.name) else { return }
        if let entity = value as? RLMObjectBase {
            toBeDeleted.insert(entity)
        } else if let list = value as? RLMSwiftCollectionBase {
            for index in 0..<list._rlmCollection.count {
                if let entity = list._rlmCollection.object(at: index) as? RLMObjectBase {
                    toBeDeleted.insert(entity)
                }
            }
        }
    }
    delete(element)
}

@verebes1
Copy link
Author

@aleyooop Thanks for your input. I've updated the Gist with your suggestion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment