绕过核心数据堆栈

时间:2014-10-22 03:05:24

标签: ios core-data

我仍然在努力解决核心数据堆栈中传递对象的最佳方法。我是如何开始参考的:

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

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

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

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

  5. 我认为可以管理MOC分布的'CoreDataStack'对象的想法可能是一个好主意。这样至少该对象可以抽象出我选择实现线程堆栈的方式的实现细节。 I.E.提供排除主要MOC和背景MOC的方法。

    在我开始思考如何传递这个堆栈对象之前,这看起来很棒。我可以完全按照苹果推荐的那样做,并将其从控制器传递给控制器​​,将主线程MOC注入每个视图控制器。但正如我上面所说的那样,在故事板上重新工作大约5分钟就会让这种情况迅速崩溃。更不用说将MOC传递给不真正需要它的视图,这样它们就可以传递到层次结构中可能需要它的下一个视图。

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

2 个答案:

答案 0 :(得分:1)

你说

  

应用程序开始变得更复杂,最终意识到为什么将MOC存储在App Delegate中是一个坏主意。

你究竟对此不喜欢什么?对于你提到的问题,app delegate或singleton是非常合适的解决方案。我只是从

的所有控制器中删除应用程序委托代码
  • 不需要核心数据
  • 将对象作为ivar(您可以从托管对象子类获取托管对象上下文)

除非你有很多记录并且需要一个获取结果控制器,否则你可以使用没有获取请求的对象图,因此核心数据层很好地被抽象掉了#34;。

答案 1 :(得分:-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的次数,避免了很多复杂性。