1

我在Swift中实现了一个程序,我使用的是Core Data框架。我的应用程序已完成,但我决定重构Core Data Stack。现在我Core Data Stack的结构是这样的:核心数据栈结构

enter image description here

我接过一看Core Data Stack形式大牧场书呆子和Github上一些其他球员,大部分时间,他们Core Data Stack看起来是这样的:

enter image description here

我想知道是否有更好的方式来重构我Core Data Stack以类似的方式。概括地说,这是我在用我的Managed Object Context为:

  • mainContext =所有UI相关的任务
  • firstPrivateContext =从火力地堡导入所有数据,并在数据推动持久性存储登录
  • secondPrivateContext =从设备导入联系人到核心数据在登录和注册
  • thirdPrivateContext =为使用该应用程序
012的过程中,从火力听传入的数据

所以这就是我的应用程序大致在做什么。如果有人知道更好的方式,我愿意接受任何建议。

这是我使用的代码,当用户再次上线日志:

func importDataFromFirebase(){ 
guard let importContext = importContext else {return} 
FirebaseStore.rootRef.childByAppendingPath("users/"+FirebaseStore.rootRef.authData.uid+"/forums").observeSingleEventOfType(.Value, withBlock:{ 
    snapshot in 
    guard let firebaseData = snapshot.value as? NSDictionary else {return} 
    guard let uids = firebaseData.allKeys as? [String] else {return} 
    importContext.performBlock{ 
     for uid in uids{ 
      guard let forum = NSEntityDescription.insertNewObjectForEntityForName("Forum", inManagedObjectContext: importContext) as? Forum else {return} 
      FirebaseStore.rootRef.childByAppendingPath("forums/"+uid+"/posts").queryOrderedByKey().observeSingleEventOfType(.Value, withBlock: { 
       snapshot in 
          // Saving the chat's messages 
          guard let data = snapshot.value as? NSDictionary else {return} 
          importContext.performBlock{ 
        guard let posts = NSEntityDescription.insertNewObjectForEntityForName("Post", inManagedObjectContext: importContext) as? Post else {return} 
        do{ 
              try importContext.save() 
             }catch let error{ 
         // Error 
             } 
       } 
      }) 
     } 
    } 
}) 
} 

此图显示了什么,我想实现:

enter image description here

回答

1

你可以建立CoreData以任何方式堆叠,但首先回答这个问题 - 你想达到什么样的行为。 如果您想在导入某些东西时自动更新UI,那么您的解决方案将无法工作。

persistent store coordinator之后的private managed object context之后的整点是在后台队列中保留重操作(保存到文件)。

如果您希望在导入屏幕后立即在屏幕上看到更新,您应该导入child private managed object context,其中parentContext设置为main managed object context。并且为了更新UI,您可以使用NSFetchedResultsController。这样,只要你在child managed object context保存 - 它会触发通知将由NSFetchedResultsController处理和更新用户界面。

不要忘记保存完整的堆栈。将保存为child managed object context保存到文件中是不够的。

建议写一些方法来保存完整的堆栈,像这样的:

- (void)saveWithCompletionBlock:(void (^)(NSError *error))completionBlock { 

    static dispatch_queue_t queue = NULL; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     queue = dispatch_queue_create("CoreDataSaveQueue", 0); 
    }); 

    //Retain current NSManagedObjectContext to avoid unloading 
    __block NSManagedObjectContext *strongSelf = self; 
    dispatch_async(queue, ^{ 

     __block NSManagedObjectContext *context = strongSelf; 
     __block NSError *error = nil; 

     do { 

      [context performBlockAndWait:^{ 

       if (context != nil && [context hasChanges]) 
        [context save:&error]; 

       context = (nil != error ? nil : context.parentContext); 
      }]; 
     } while (nil != context); 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      if (completionBlock) 
       completionBlock(error); 
     }); 

     //Release current NSManagedObjectContext after save completed 
     strongSelf = nil; 
    }); 
} 

我希望我的解释会帮助你了解你想怎么建堆。

+0

感谢您的回答。我想要实现的行为是首先从Firebase导入所有数据,并在用户登录时将其推送到持久性存储区。比登录后,我想要显示此数据并在添加到时自动更新UI核心数据或Firebase。我已经实现了最后一部分,但是我正在努力解决第一部分问题,有时候所有的数据都被导入或者只是减半。我的进口根本不健壮。我认为这也与我在用户注销时删除所有Core Data的方式有关。 – C00kieMonsta

+0

你知道为什么只有一半数据被导入了吗?你如何进口? –

+0

从你的代码中,我发现你在'for uid in uids'后面没有调用保存上下文。 我对Firebase并不是很熟悉,但据我了解,FirebaseStore.rootRef.childByAppendingPath(...)会执行异步API调用来获取所需的信息,但只有在获得第二个API调用响应后才能保存。 另外,你确定你应该调用'observeSingleEventOfType'吗?它会返回完整的数据集吗? –