ios - 如何在 Swift 中的 NSCoding 初始化时返回预先存在的核心数据对象?

标签 ios swift core-data nscoding

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

super.init(entity: ..., insertIntoManagedObjectContext: ...)

因为这会将一个对象插入到数据库中。

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
    }
}

这是一个 fairly common Objective-C 模式,但我不知道如何在 Swift 1.2 中复制它,因为将另一个对象分配给 self 会产生编译错误:

Cannot assign to 'self' in a method

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


如何在初始化时用数据库中预先存在的对象替换对象?如果它可能(如果是这种情况请提供引用),我应该改用什么模式?

最佳答案

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

You can use this method to eliminate redundant objects created by the coder. For example, if after decoding an object you discover that an equivalent object already exists, you can return the existing object. If a replacement is returned, your overriding method is responsible for releasing the receiver.

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
        }
    }
}

关于ios - 如何在 Swift 中的 NSCoding 初始化时返回预先存在的核心数据对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31372584/

相关文章:

ios - UIImageView 实时滤镜在相机预览层上拉伸(stretch)

iphone - Restkit内存不足警告

ios - 通过 UINavigationControllerDelegate 接收 ViewDidUnload 消息

ios - 关于 initWithNavigationBarClass 的困惑——如何使用(新的 instanceType 方法)

ios - 如何使多个右栏按钮项目在导航栏中垂直堆叠?

ios - 存储 UISwitch 状态的问题

cocoa - 将新元素添加到 NSManagedObject

ios - 如何使用NSExpression使用自定义函数设置NSFetchRequest propertiesToFetch

javascript - 如何在uiwebview中使用显示nsstring内容?

android - Win 7、安卓、iOS SDK