LoginSignup
3
3

More than 5 years have passed since last update.

消される前に消す!Cascade Deleteが待ちきれない人に

Posted at

背景

CoreDataではRelationshipに対してDelete Ruleを設定しておくことができます。これにより、オブジェクトを削除した際に、関連するオブジェクトを連鎖的に削除することができます。(CascadeDeleteRule)

問題点

上記のDelete Ruleは非常に便利なのですが、この処理は常に遅延して実行されます。通常はこの遅延は問題になりませんが、オブジェクトの削除直後に集計等を行うと、削除されるはずのオブジェクトが含まれてしまう場合があります。

対策

NSManagedObjectが削除される際に呼び出されるprepareForDeletionというフックがあるので、これを利用して即時にオブジェクトを削除することが出来ます。下記のコードではモデル上で設定されたDelete Ruleに基づいて削除処理を行っています。

該当オブジェクトに実装
    override func prepareForDeletion() {
        super.prepareForDeletion()
        btk_propagateDelete()
    }
NSManagedObjectのエクステンション
import CoreData

extension NSManagedObject{

    func btk_propagateDelete(){
        if(managedObjectContext == nil){
            return
        }
        let context = managedObjectContext!
        let relationships = entity.relationshipsByName
        let relationshipNames:[String] = {
            var names:[String] = []
            for name in relationships.keys{
                names.append(name as! String)
            }
            return names
        }()

        for relationshipName in relationshipNames{
            let desc = relationships[relationshipName] as! NSRelationshipDescription
            if(desc.deleteRule == .CascadeDeleteRule){
                if(desc.toMany){
                    if(desc.ordered){
                        let toMany = mutableOrderedSetValueForKey(relationshipName)
                        for obj in toMany.array as! [NSManagedObject]{
                            context.deleteObject(obj)
                        }
                    }
                    else{
                        let toMany = mutableSetValueForKey(relationshipName)
                        for obj in toMany.allObjects as! [NSManagedObject]{
                            context.deleteObject(obj)
                        }
                    }
                }
                else{
                    let obj = valueForKey(relationshipName) as! NSManagedObject
                    context.deleteObject(obj)
                }
            }
            else if(desc.deleteRule == .NullifyDeleteRule){
                if(desc.toMany){
                    if(desc.ordered){
                        let toMany = mutableOrderedSetValueForKey(relationshipName)
                        toMany.removeAllObjects()
                    }
                    else{
                        let toMany = mutableSetValueForKey(relationshipName)
                        toMany.removeAllObjects()
                    }
                }
                else{
                    setValue(nil, forKey: relationshipName)
                }
            }
        }
    }

}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3