ios - 使用 CoreData 托管对象进行依赖注入(inject)的推荐方法?

标签 ios swift core-data

鉴于我有一个由 CoreData 堆栈管理的类, 我目前正在编写一个框架,我希望能够通过依赖注入(inject)(理想情况下,仅通过 DI)创建我的对象。

我还以“快速失败”的心态(即尽快崩溃)进行设计,并严格遵循 SOLID 原则。

该框架将兼容 iOS 9-10,并且可以在 ObjC 和 Swift(或混合目标)中使用,因此我理想情况下不想依赖 ObjC 或 Swift 中的非交叉兼容功能。

这段代码旨在内部使用,而不是像Jonah那样暴露给框架的使用者。指出公开此类功能并不是一个非常可靠的选择。

问题:

我有两种不同的方法来创建我的对象,我不确定是否 如果存在“首选”解决方案,或者使用中陷阱较少的解决方案,那么它们中的任何一个都是正确的?

这是一个代码片段来说明我的情况:

import CoreData
class Example: NSManagedObject {}

class DependencyClass: NSObject {}

extension Example
{
    public convenience init(with someDependency:DependencyClass,
                            context:NSManagedObjectContext)
    {
        let description = NSEntityDescription.entity(forEntityName: "Example", in: context)
        self.init(entity: description!, insertInto: context)
        //Configure the result object here
    }

    class func NotAConvenienceInit(with someDependency:DependencyClass,
                       context:NSManagedObjectContext) -> Example
    {
        let selfClassName = String(describing: self)
        let result = NSEntityDescription.insertNewObject(forEntityName: selfClassName, into: context) as! Example
        //Configure the result object here
        return result
    }
}

let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
let dependency = DependencyClass()

//Usecase A
let myExample = Example(with: dependency, context: context)

//Usecase B
let anotherExample = Example.NotAConvenienceInit(with: dependency, context: context)

为了方便 init,我一直在考虑可失败的初始化程序,我对这样的想法很感兴趣:一旦 init 方法结束,我就“保证”我的对象是有效的。我认为这两种方式都可以通过各种机制来保证。

Apple 似乎更喜欢 their documentation 中的 +insertNewObjectForEntityForName:inManagedObjectContext:这就是我想出这两种方法的原因。

PS:我仍在学习 Swift,如果这看起来是一个已经解决的问题,我提前表示歉意。在阅读了各个网站上的许多文章后,我没有找到结论性的解决方案,因此转向 SO。

最佳答案

我尝试做同样的事情,我的结论是,最好避免这种方法,而是保留行为,特别是需要模型的其他依赖项的行为。

为什么?

  1. Swift 和 Objective-C 确实没有为您提供任何工具来禁止使用现有的构造函数,因此虽然您可以使用 DI 参数提供替代方案,但您几乎无法确保 NSManagedObjectNSEntityDescription 不用于创建模型的实例。

  2. 另外 NSManagedObject.init(entity:insertInto:)NSEntityDescription.insert​New​Object(for​Entity​Name:​into:​)用于插入新的模型实例,但不是创建模型类实例的唯一方法。看看 NSManagedObjectawake​From​Fetch()awake(from​Snapshot​Events:​) (以及 从Insert()唤醒)。

    假设我创建一个 NSFetchedResultsController ,其中的获取请求返回您的框架模型之一。如果我调用controller.fetchedObjects,我将获得您的模型的实例。同样,我可以直接执行 NSFetchRequest 。您可以使用单例容器在 awake... 实现中提供依赖项,但这限制了创建代码指定这些依赖项的能力,并导致另一个问题:

  3. 托管对象上下文队列。由于 NSManagedObjects 与内容绑定(bind)并且必须在该上下文的队列上使用,因此您需要注意引入对错误队列上的模型的访问的依赖项,并且通常希望依赖项范围仅限于特定上下文。

相反,我会考虑:

  • 让您的框架返回非 NSManagedObject 模型,这些模型是核心数据存储中的状态快照(可能是不可变的)。如果您可以避免向框架的使用者公开核心数据的使用,那么您可以为他们提供不受特定并发队列限制的模型,并且您可以完全拥有这些模型的生命周期。
  • 避免模型中的任何外部依赖关系,并将此类行为移至服务类或其他接口(interface)中,以便更轻松地使用 DI。确保这些服务类尊重它们所给定的任何模型的并发队列,因此您的所有接口(interface)可能都需要异步。

关于ios - 使用 CoreData 托管对象进行依赖注入(inject)的推荐方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43187929/

相关文章:

iOS 导航栏高度

ios - 静态库上的 Xib 文件

xcode - 我应该使用 CoreData 谓词来填充我的 UITableview 吗?

ios - [ valueForUndefinedKey :]: this class is not key value coding-compliant for the key appointmentDate. '-swift

core-data - 如何在 Intent Handler 中使用获取数据来编辑 Widget iOS 14?

ios - 在 CoreData 中建立关系

ios - iPhone + UITableView

ios - iOS 上的线性加速如何获得与 Android TYPE_LINEAR_ACCELERATION 相同的数据?

ios - 将框架和应用程序扩展目标添加到 IOS 应用程序项目,我做得对吗?

ios - 在 Swift 中无限期地旋转 View 360 度?