Swift:CoreData NSManagedObject 的自定义设置器

Posted

技术标签:

【中文标题】Swift:CoreData NSManagedObject 的自定义设置器【英文标题】:Swift: Custom Setter For CoreData NSManagedObject 【发布时间】:2014-09-08 03:56:47 【问题描述】:

如何在 Swift 中为 NSManagedObject 实现自定义设置器。我需要在设置NSMangedObject 属性之前完成任务。

【问题讨论】:

【参考方案1】:

我的建议是使用 KVC。也许不是最优雅的解决方案,但在概念上是 KVC 的逻辑应用。

观察属性的变化。在init(entity:insertIntoManagedObjectContext:) 中注册更改,或者在awakeFromFetchawakeFromInsert 中注册更改,并在willTurnIntoFault 中删除观察者。

init(entity: NSEntityDescription!, insertIntoManagedObjectContext context: NSManagedObjectContext!) 
    super.init(entity: entity, insertIntoManagedObjectContext: context)
    addObserver(self, forKeyPath: "attribute", options: NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Old, context: nil)



override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: NSDictionary!, context: CMutableVoidPointer) 
    if (keyPath == "attribute") 
           // do what you need to do
    


为 Swift 3 更新:

init(entity: NSEntityDescription!, insertIntoManagedObjectContext context: NSManagedObjectContext!) 
    super.init(entity: entity, insertIntoManagedObjectContext: context)
    addObserver(self, forKeyPath: "attribute", options: [.old, .new], context: nil)


override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 
    if keyPath == "attribute" 
           // do what you need to do
    

【讨论】:

特别是这解决了我的问题options: NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Old。谢谢。 我认为如果 NSManagedObject 出现故障,KVO 方法将会崩溃。【参考方案2】:

还有一种更简单的方法可以在不管理 KVO 订阅的情况下完成此操作。只需像这样覆盖 didChangeValueForKey: 即可完成:

 override func didChangeValueForKey(key: String) 
    super.didChangeValueForKey(key)

    if key == "propertyName" 
        // do something now when propertyName changed
    

【讨论】:

我也使用过这个,不幸的是,当你查看文档时,你会注意到You must not override this method. 警告。所以我想这可能会产生一些意想不到的影响。 @erikAigner 这是真的。我使用这种方法已经有一段时间了,我相信文档中的警告主要是出于性能问题,因为整个 KVO/KVC 都在使用这种方法(连同willChangeValueForKey:)。建议 KVO 的公认答案与这个具有相同的性能特征。到目前为止,我还没有发现使用这种方法的任何意外副作用。【参考方案3】:

TL;DR

我建议覆盖awakeFromInsert 而不是init,因为它不需要KVO 并且可以安全地访问对象属性。覆盖任何 init 方法是有风险且不必要的,因为对象及其属性可能尚未准备好被访问(故障)。

说明

重写任何init 方法是有风险且不必要的,因为对象及其属性可能尚未准备好被访问(故障)。然而,在它开始接受数据之前准备一个NSManagedObject 是非常有用的。也许我们想在将对象交给用户之前设置一些逻辑默认值或分配一些关系。在这些情况下,我们使用awakeFromInsert。顾名思义,这个方法是在通过插入调用创建NSManagedObject 之后立即调用的。

此方法在设置任何值之前调用,是设置默认值、初始化瞬态属性和执行我们通常在init 方法中处理的其他任务的绝佳机会。此方法在对象的整个生命周期中仅调用一次。它不会在应用程序的下一次执行时被调用,并且在从持久存储中读入对象时也不会被调用。因此,我们不需要担心覆盖之前设置的值。当我们重写这个方法时,我们应该确保在我们实现的最开始就调用super.awakeFromInsert(),以允许NSManagedObject在我们开始我们的代码之前完成它需要做的任何事情。

Xcode Snippets (Xcode 12) 中的便捷 ObjC 快捷方式

注意:为此手动添加您自己的 Swift sn-p 非常容易。你也可以尝试一些 GH repo。例如Swift 4 snippets。

【讨论】:

以上是关于Swift:CoreData NSManagedObject 的自定义设置器的主要内容,如果未能解决你的问题,请参考以下文章

其他对象中未显示的对象属性

Core Data 获取关系对象

将 CoreData 保存到 iCloud (Swift)

Swift/IOS/CoreData:如何在自动生成的 CoreData 类中将 var 定义为枚举类型?

Swift 构建 CoreData,语义问题

Swift - 删除CoreData行[重复]