鉴于我有一个由 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。
最佳答案
我尝试做同样的事情,我的结论是,最好避免这种方法,而是保留行为,特别是需要模型的其他依赖项的行为。
为什么?
Swift 和 Objective-C 确实没有为您提供任何工具来禁止使用现有的构造函数,因此虽然您可以使用 DI 参数提供替代方案,但您几乎无法确保
NSManagedObject
或NSEntityDescription
不用于创建模型的实例。另外
NSManagedObject.init(entity:insertInto:)
和NSEntityDescription.insertNewObject(forEntityName:into:)
用于插入新的模型实例,但不是创建模型类实例的唯一方法。看看NSManagedObject
的awakeFromFetch()
和awake(fromSnapshotEvents:)
(以及从Insert()唤醒
)。假设我创建一个
NSFetchedResultsController
,其中的获取请求返回您的框架模型之一。如果我调用controller.fetchedObjects,我将获得您的模型的实例。同样,我可以直接执行NSFetchRequest
。您可以使用单例容器在awake...
实现中提供依赖项,但这限制了创建代码指定这些依赖项的能力,并导致另一个问题:托管对象上下文队列。由于
NSManagedObjects
与内容绑定(bind)并且必须在该上下文的队列上使用,因此您需要注意引入对错误队列上的模型的访问的依赖项,并且通常希望依赖项范围仅限于特定上下文。
相反,我会考虑:
- 让您的框架返回非 NSManagedObject 模型,这些模型是核心数据存储中的状态快照(可能是不可变的)。如果您可以避免向框架的使用者公开核心数据的使用,那么您可以为他们提供不受特定并发队列限制的模型,并且您可以完全拥有这些模型的生命周期。
- 避免模型中的任何外部依赖关系,并将此类行为移至服务类或其他接口(interface)中,以便更轻松地使用 DI。确保这些服务类尊重它们所给定的任何模型的并发队列,因此您的所有接口(interface)可能都需要异步。
关于ios - 使用 CoreData 托管对象进行依赖注入(inject)的推荐方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43187929/