Swift 2.0中后台线程中的CoreData。干净的方式?

时间:2016-03-04 23:22:53

标签: swift core-data

我已经在这个问题上苦苦挣扎了8天了。所以我相信现在是时候向大师们寻求帮助了。

好的,所以我试图在Uncle Bob的Clean Architecture之后实现一个应用程序,所以我设置了ViewControllers,Models,Interactors,Repositories和Presenters。

我的AppDelegate中没有任何CoreData痕迹,没有。所有这些都在MyAppCoreData类中完成。

存储库注入AppDelegate,Interactor访问注入的对象,不仅可以访问CoreData,还可以访问Parse和其他私有API。 Parse和私有API工作得很好。 CoreData存储库也“有效”。它不会抛出任何异常。但是在CoreData中没有插入数据,当我获取时,它是空的。

我相信我在持久存储协调员+主要上下文+私有上下文方面遇到了一些问题......但还没有找到它是什么。

让我们转到代码:

的AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate {    
    var window: UIWindow?

    let container = Container() { c in
        c.register(UserDataStore.self) { _ in ParseRepository() } 
        c.register(BabyNamesDataStore.self) { _ in BabyNameRepository.sharedInstance }
        c.register(GenericRepository.self) { r in
            GenericRepository(_userDataStore: r.resolve(UserDataStore.self)!,  _babyNameDataStore: r.resolve(BabyNamesDataStore.self)!)
        }
    }
...

然后,我的交互者有以下init()函数:

class MainInteractor: MainInteractorInput
{
    var output: MainInteractorOutput!
    var worker: GenericRepository?

    init() {
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        worker = appDelegate.container.resolve(GenericRepository.self)
    }

然后,最后,我的 CoreDataStore 是一个单例(在它之前没有,我可以看到它由于某种原因被Swinject实例化了两次):

class BabyNamesCoreDataStore : BabyNamesDataStore{

    var mainManagedObjectContext: NSManagedObjectContext
    var privateManagedObjectContext: NSManagedObjectContext

    static let sharedInstance = BabyNamesCoreDataStore()

    init()
    {
        QL1("BabyNamesCoreDataStore init")
        // This resource is the same name as your xcdatamodeld contained in your project.
        guard let modelURL = NSBundle.mainBundle().URLForResource("BabyNameMe", withExtension:"momd") else {
            fatalError("Error loading model from bundle")
        }

        // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
        guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else {
            fatalError("Error initializing mom from: \(modelURL)")
        }

        let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
        mainManagedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
        mainManagedObjectContext.persistentStoreCoordinator = psc

        let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
        let docURL = urls[urls.endIndex-1]
        /* The directory the application uses to store the Core Data store file.
        This code uses a file named "DataModel.sqlite" in the application's documents directory.
        */
        let storeURL = docURL.URLByAppendingPathComponent("BabyNameMe.sqlite")
        do {
            try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)
        } catch let error as NSError  {
            QL4("Could not save \(error), \(error.userInfo)")
            fatalError("Error migrating store: \(error)")
        }

        //let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        privateManagedObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
        privateManagedObjectContext.parentContext = mainManagedObjectContext

    }

    deinit
    {
        do {
            try self.mainManagedObjectContext.save()
        } catch {
            fatalError("Error deinitializing main managed object context")
        }
    }


    func fetchBabyNames(completionHandler: (babyNames: [BabyNames], error: StoreError?) -> Void) {
        privateManagedObjectContext.performBlock {
            do {
                let fetchRequest = NSFetchRequest(entityName: "ManagedBabyNames")
                let predicate = NSPredicate(format: "liked == nil")
                fetchRequest.predicate = predicate
                let results = try self.privateManagedObjectContext.executeFetchRequest(fetchRequest) as! [ManagedBabyNames]
                let result = results.map { $0.toBabyName() }
                completionHandler(babyNames: result, error: nil)
            } catch let error as NSError  {
                QL4("Could not save \(error), \(error.userInfo)")
                completionHandler(babyNames: [], error: StoreError.CannotFetch("Cannot fetch baby names"))
            }
        }
    }
func insertBabyNames(babyNames: BabyNames, completionHandler: (error: StoreError?) -> Void) {
        privateManagedObjectContext.performBlock {
            do {
                let managedBabyNames = NSEntityDescription.insertNewObjectForEntityForName("ManagedBabyNames", inManagedObjectContext: self.privateManagedObjectContext) as! ManagedBabyNames
                managedBabyNames.fromBabyName(babyNames)
                try self.privateManagedObjectContext.save()
                completionHandler(error: nil)
            } catch let error as NSError  {
                QL4("Could not save \(error), \(error.userInfo)")
                completionHandler (error: StoreError.CannotCreate("Cannot create baby names with id \(babyNames.id)"))
            }
        }
    }
...

这就是它。我没有例外,但它根本不起作用。 谁能帮助这个绝望的男人? :)

谢谢!

更新

我正在关注Raymund的Clean Store创意,以实现我自己的想法,在这里找到:https://github.com/Clean-Swift/CleanStore

我发现在View Controller中接收来自Presenter的响应的函数不在主线程中。所以我不得不补充一下:

func displaySomething(viewModel: LoginViewModel) {
        if viewModel.loginStatus {
            let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
            appDelegate.prepareSlideOutVC()
            //When user is not logged in, the SlideOut Menu is not loaded. So when he logs in, we must load it.
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
                dispatch_async(dispatch_get_main_queue()) {
                    self.router.navigateToMainScene()
                }
            }
        } 
    }

添加dispatch_async在一些情况下解决了问题,但并非所有情况......仍然试图弄明白。 所以,基本上,在我登录并收到Presenter的响应之后,我激活了segue以转到MainVC,但那是在另一个线程中。 仍在尝试解决这个问题。

0 个答案:

没有答案