如何在 Swift 的 NSCoding 初始化中返回预先存在的核心数据对象?
Posted
技术标签:
【中文标题】如何在 Swift 的 NSCoding 初始化中返回预先存在的核心数据对象?【英文标题】:How do I return a pre-existing Core Data object at NSCoding initialization in Swift? 【发布时间】:2015-07-12 21:04:26 【问题描述】:当我的类的实例使用NSCoding
初始化时,我想将其替换为Core Data 数据库中的现有 对象,而不是调用:
super.init(entity: ..., insertIntoManagedObjectContext: ...)
因为这会在数据库中插入一个 new 对象。
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
会产生编译错误:
不能在方法中分配给'self'
即使它确实成功了,似乎 Swift 要求我调用 NSManagedObject
的指定初始化程序,它将一个 new 对象插入数据库。
如何在初始化时将对象替换为数据库中预先存在的对象?如果它 not 可能(如果是这种情况,请提供参考),我应该使用什么模式?
【问题讨论】:
我认为根据语言的“安全特性”,swift 中根本不允许使用这个成语。 【参考方案1】:您可以使用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
【讨论】:
我不敢相信我错过了!谢谢! 万一我需要与上下文中的其他对象建立关系(最好是在初始化时),是否可以在super.init
中指定一个上下文,然后在这种情况下调用ctx.deleteObject(self)
我们用存储中的一个替换整个对象?
警告对于以后可能会看到这篇文章的任何人:我花了比我愿意承认的时间更多的时间来尝试调试一个似乎是由将nil
传递给insertIntoManagedObjectContext
参数的初始化程序。似乎通过nil
(并改为插入awakeAfterUsingCoder
)可能会产生一些似乎是错误的副作用,尤其是在多上下文环境中。以上是关于如何在 Swift 的 NSCoding 初始化中返回预先存在的核心数据对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何让我的简单对象符合 Swift 中的 NSManagedObject 和 NSCoding
Swift 中 SKProduct 的 NSCoding 错误