如何在Swift的NSCoding初始化中返回预先存在的Core Data对象?

San*_*aus 10 core-data nscoding ios swift

当使用我的类初始化我的类的实例时NSCoding,我想用Core Data数据库中的现有对象替换它而不是调用:

super.init(entity: ..., insertIntoManagedObjectContext: ...)
Run Code Online (Sandbox Code Playgroud)

因为那会将对象插入数据库.

class MyClass: NSManagedObject, NSCoding {
    required init(coder aDecoder: NSCoder) {
        // Find a preexisting object in the Core Data database

        var ctx = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
        var fs = NSFetchRequest(entityName: "MyClass")

        // ... Configure the fetch request based on values in the decoder

        var err: NSErrorPointer = nil
        var results = ctx.executeFetchRequest(fs, error: err)

        // ... Error handling, etc

        newObject = results[0] as! MyClass

        // Attempt to replace self with the new object
        self = newObject // ERROR: "Cannot assign to 'self' in a method"
    }

    func encodeWithCoder(aCoder: NSCoder) {
        // Encode some identifying property for this object
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个相当常见的 Objective-C模式,但我无法弄清楚如何在Swift 1.2中复制它,因为分配另一个对象会self产生编译错误:

无法在方法中分配给"self"

即使它确实成功了,似乎Swift要求我调用NSManagedObject指定的初始化程序,它将一个对象插入到数据库中.


如何在初始化时用数据库中预先存在的对象替换对象?如果它能够(请提供一个参考,如果是这样的话),我应该用什么来代替格局?

rin*_*aro 2

您可以用于awakeAfterUsingCoder(_:)替换self

您可以使用此方法来消除编码器创建的冗余对象。例如,如果在解码对象后发现等效对象已存在,则可以返回现有对象。如果返回替换,您的重写方法将负责释放接收器。

class Item: NSManagedObject, NSCoding {

    @NSManaged var uuid: String
    @NSManaged var name: String?

    override init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?) {
        super.init(entity: entity, insertIntoManagedObjectContext: context)
    }

    required init(coder aDecoder: NSCoder) {
        let ctx = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
        let entity = NSEntityDescription.entityForName("Item", inManagedObjectContext: ctx)!

        // Note: pass `nil` to `insertIntoManagedObjectContext`
        super.init(entity: entity, insertIntoManagedObjectContext: nil)
        self.uuid = aDecoder.decodeObjectForKey("uuid") as! String
    }

    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(self.uuid, forKey: "uuid")
    }

    override func awakeAfterUsingCoder(aDecoder: NSCoder) -> AnyObject? {
        let ctx = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
        let fetch = NSFetchRequest(entityName: "Item")
        fetch.predicate = NSPredicate(format: "uuid == %@", self.uuid)

        if let obj =  ctx.executeFetchRequest(fetch, error: nil)?.first as? Item {
            // OK, the object is still in the storage.
            return obj
        }
        else {
            // The object has already been deleted. so insert and use `self`.
            ctx.insertObject(self)
            return self
        }
    }
}
Run Code Online (Sandbox Code Playgroud)