使用CoreData受管对象进行依赖关系注入的推荐方法? [英] Recommended way to do Dependency Injection with CoreData managed objects?

查看:35
本文介绍了使用CoreData受管对象进行依赖关系注入的推荐方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Given that I have a class managed by the CoreData stack, I am currently writing a Framework, and I want to be able to create my objects through dependency injection (ideally, only through DI).

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

I am also designing with "fail fast" mentality (i.e. crash as soon as possible), and following closely SOLID principles.

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

That framework will be iOS 9-10 compatible, and could be used in either ObjC and Swift (or mixed targets), therefore I ideally do not want to rely on non cross compatible features in either ObjC or Swift.

这部分代码应在内部使用,并且不会如 Jonah 所述,暴露给框架的使用者暴露出这样的功能并不是一个很可靠的选择.

This piece of code is meant to be used internally, and not exposed to the consumer of the framework as Jonah points out that exposing such functionalities is not a very solid choice.

我在这里有2种不同的方式来创建我的对象,我不确定是否如果有首选"的解决方案,或者使用中的陷阱少,它们中的哪一个是正确的?

I have here 2 different ways to create my object, and I am not sure if either of them are corrects, if there is a "preferred" solution, or one that has less pitfalls in usage ?

下面是一个代码片段,用以说明我的情况:

Here is a code snippet to illustrate my case :

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)

为了方便的初始化,我一直在考虑失败的初始化程序,我对这样的想法很着迷,即一旦初始化方法结束,我将保证"我的对象是有效的.我认为这两种方式都可以通过各种机制来保证.

I have been thinking about failable initializers for the convenience init, I am quite seduced by the idea that once the init method is over, I am "guaranteed" my object is valid. I think both ways can guarantee that through various mechanisms.

Apple似乎更喜欢+ insertNewObjectForEntityForName:inManagedObjectContext:"rel =" nofollow noreferrer>他们的文档,这就是为什么我想出了这两种方法.

Apple seems to prefer +insertNewObjectForEntityForName:inManagedObjectContext: in their documentation and that is why I came up with those 2 methods.

PS:我仍然在学习Swift,如果这似乎已经解决了问题,请提前道歉.在阅读了各种网站上的许多文章之后,我没有找到一个最终的解决方案,因此转向了SO.

PS : I'm still learning Swift, my apologies in advance if this seems like an already solved question. After reading many articles on various websites, I did not find a conclusive solution, and therefore am turning to SO.

推荐答案

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

I've tried to do the same thing and my conclusion was that it's better to avoid this approach and instead keep behavior, especially behavior which requires other dependencies off of the models.

为什么?

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

  1. Swift and Objective-C really don't give you any tools to prohibit the use of existing constructors so while you can provide alternatives with your DI arguments there's very little you can do to ensure that NSManagedObject or NSEntityDescription are not used to create instances of your model.

另外 NSManagedObject.init(entity:insertInto:) NSEntityDescription.insertNew Object(forEntityName:into:)用于插入新的模型实例,但不是创建模型类实例的唯一方法.看看 NSManagedObject awake \ FromFetch() awake(fromSnapshotEvents:)(和从``插入())唤醒.

Additionally NSManagedObject.init(entity:insertInto:) and NSEntityDescription.insert​New​Object(for​Entity​Name:​into:​) are used to insert new model instances but are not the only ways in which instances of your model classes can be created. Take a look at NSManagedObject's awake​From​Fetch() and awake(from​Snapshot​Events:​) (and awake​From​Insert()).

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

Suppose I create a NSFetchedResultsController with a fetch request returning one of your framework models. If I call controller.fetchedObjects I'll get instances of your model. Similarly I could execute a NSFetchRequest directly. You might use a singleton container to supply dependencies in an awake... implementation but that limits the creating code's ability to specify those dependencies and leads to another problem:

受管对象上下文队列.由于 NSManagedObjects 已绑定到内容,并且必须在该上下文的队列中使用,因此您需要当心依赖项,从而在错误的队列上引入对模型的访问,并且通常希望依赖项的范围仅限于特定上下文.>

Managed object context queues. Since NSManagedObjects are tied to a content and must be used on that context's queue you need to watch out for dependencies introducing access to a model on the wrong queue and often want dependencies scoped to a particular context.

相反,我会考虑:

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

这篇关于使用CoreData受管对象进行依赖关系注入的推荐方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆