【问题标题】:Passing around Core Data Stack传递核心数据堆栈
【发布时间】:2014-10-22 03:05:23
【问题描述】:

我仍在为在核心数据堆栈中传递对象的最佳方式而苦苦挣扎。我是如何开始参考的:

  1. 应用程序超级简单,单线程核心数据访问非常完美,只有几个视图,每个视图都需要一个 MOC。从创建核心数据堆栈和一个 MOC 的示例代码开始。 MOC 存储在 App Delegate 中。

  2. App 开始变得更加复杂,终于意识到为什么将 MOC 存储在 App Delegate 中是个坏主意。重构代码以在 App Delegate 中创建 MOC 并将 MOC 注入根视图控制器。从那里,App Delegate 没有保留 MOC,视图控制器将其注入可能需要它的其他控制器。

  3. 开始重构故事板中的应用程序视图。新的标签栏,一些导航控制器,拆分视图控制器,你知道的只是一些不同的想法。步骤#2变成了一场噩梦。每次我对故事板中的应用程序视图层次结构进行更改时,我都必须修改每个视图控制器以通过新的层次结构传递 MOC。苹果肯定说这是正确的方法,但我不确定我是否购买它,很难在不杀死代码的情况下进行简单的视图层次结构更改。现在我在我的应用程序开始时有 4 个视图,它们甚至不需要 MOC。然而,这些视图是从应用程序委托到确实需要 MOC 的视图控制器的唯一链接。所以我坚持将 MOC 注入所有这些视图控制器,这样他们就可以将其传递给另一个视图控制器,而无需每次都使用 MOC。

  4. 应用程序更加复杂,现在我想要一个线程化的核心数据堆栈。这意味着传递持久存储,以便某些“处理”对象可以在后台线程上创建自己的 MOC。我应该创建某种可以帮助管理这个的 CoreDataStack 对象吗? IE。我可以要求主线程 MOC 或要求新的“工人”背景 MOC 的对象。似乎现在第 3 步更没有意义了,我的意思是我的应用程序中的每个视图都需要访问主线程 MOC,仅此而已。我想我暂时看不到这个改变,但谁知道自从我开始以来我已经改变了很多;)

我认为可以管理 MOC 分布的“CoreDataStack”对象的想法可能是一个好主意。这样,至少该对象可以抽象出我选择实现线程堆栈的方式的实现细节。 IE。提供主要的 MOC 和后台 MOC 的方法。

在我开始考虑如何传递这个堆栈对象之前,这似乎很棒。我可以完全按照苹果的建议去做,并将其从控制器传递到控制器,将主线程 MOC 注入每个视图控制器。但正如我在上面所说的那样,在故事板中大约 5 分钟的重新工作会使它很快就崩溃了。更不用说将 MOC 传递给实际上并不需要它的视图,以便它们可以传递给层次结构中可能需要它的下一个视图。

最后是我的问题。对于我的用例是否有更好的解决方案,而不是将 MOC 传递/注入到每个视图控制器中???

【问题讨论】:

  • 在多线程环境中使用 Core Data 和对象会变得相当复杂。看看Magical Record,它可以消除很多痛苦。 github.com/magicalpanda/MagicalRecord
  • 2 是首选方式,尤其是在使用嵌套上下文时。您可以通过使用非正式协议使您的实现稍微容易一些。如果您遵循规则并为不同的工作主体创建新的上下文,并发性不应该带来问题。 quellish.tumblr.com/post/97430076027/…

标签: ios core-data


【解决方案1】:

你说

App 开始变得越来越复杂,终于意识到为什么将 MOC 存储在 App Delegate 中是个坏主意。

你到底有什么不喜欢的?对于您提到的问题,应用程序委托或单例是非常合适的解决方案。我会从所有控制器中删除应用程序委托代码

  • 不需要核心数据
  • 将对象作为 ivar(您可以从托管对象子类中获取托管对象上下文)

除非您有大量记录并且需要获取结果控制器,否则您可以只使用对象图而不需要获取请求,因此核心数据层很好地“抽象”了。

【讨论】:

    【解决方案2】:

    我使用的一种新技术是代理对象。基本上我所做的是制作一个模仿托管对象的struct。对于所有的读取操作,我使用这个模拟对象。如果用户正在编辑数据但尚未“保存”它,我也使用模拟对象。只有当用户承诺保存对象时,我才会使用 Core Data。那时我会调用在这里创建的 MOC 单例,

    // My `AppDelegate` conforms to `UIApplicationDelegateWithPSC`
    protocol UIApplicationDelegateWithPSC {
    
        func providePersistentStoreCoordinator() -> NSPersistentStoreCoordinator
    
    }
    
    class ContextManager {
    
        static let sharedInstance = ContextManager(concurrencyType: .mainQueueConcurrencyType)
    
        private init(concurrencyType: NSManagedObjectContextConcurrencyType ) { }
    
        lazy var context: NSManagedObjectContext = {
           return {
            let modelURL = Bundle.main.url(forResource: "Foo", withExtension: "momd")
            let mom = NSManagedObjectModel(contentsOf: modelURL!)
            let appDelegateWithPSC = UIApplication.shared.delegate as! UIApplicationDelegateWithPSC
            let psc = appDelegateWithPSC.providePersistentStoreCoordinator()
            let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
            let storeURL = (urls[urls.endIndex-1]).appendingPathComponent("Bar")
            var error: NSError? = nil
            var store: NSPersistentStore?
            do {
                store = try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
            } catch let error1 as NSError {
                error = error1
                store = nil
            } catch {
                fatalError()
            }
            let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
            managedObjectContext.persistentStoreCoordinator = psc
    
            return managedObjectContext
           }()
         }()
    
    }
    

    我将上下文称为:

         ContextManager.sharedInstance.context.performAndWait({
            do {
                let foo = NSEntityDescription.insertNewObject(forEntityName: "Foo", into:  ContextManager.sharedInstance.context) as? Foo
                // `mimicStruct` is the struct i've been using to avoid the headaches of complying with rules for manipulating ManagedObjects.
                foo?.name = mimicStruct.name
                try ContextManager.sharedInstance.context.save()
    
            } catch {
    
            }
        })
    

    通过在我的上下文中使用单例对象,我避免了多线程代码的复杂性。请注意,我也将其设为performAndWait,这意味着我正在阻塞,但由于我仅在读取/写入数据库时​​才这样做,因此用户通常希望在微调器指示Loading...Saving... 时稍作停顿.我最终减少了前往MOC 的次数,并避免了很多复杂性。

    【讨论】:

    • 我需要整个上下文,而不仅仅是 id,即 tableviews 等。仍然到处传递一些东西,Ids,MOC 相同的区别,进行故事板更改并返回到大量代码更新。
    • 澄清一下,WWDC 2014 会议@Vader 提到了核心数据并发模型的历史,而不是如何传递上下文本身的历史。
    猜你喜欢
    • 1970-01-01
    • 2017-05-23
    • 1970-01-01
    • 2020-10-09
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多