2014-01-16 18 views
0

在magicalRecord [在iOS 7应用]有两种NSManagedObjectContexts:MagicalRecord ==总背景?

  1. 类型的RootSavingContext NSPrivateQueueConcurrencyType
  2. 类型的DefaultContext NSMainQueueConcurrencyType

虽然做一个非常沉重的数据库[.sqlite]插入/更新/删除 如何使用上述两种上下文,使得 数据库保存[最终磁盘I/O]也在后台 中发生,并且不使用主线程。 眼下在MagicalRecord

+ (void)rootContextChanged:(NSNotification *)notification { 
if ([NSThread isMainThread] == NO) { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self rootContextChanged:notification]; 
    }); 

    return; 
} 

[[self MR_defaultContext] mergeChangesFromContextDidSaveNotification:notification]; 

}

的代码使用主线程将数据保存到数据库中。 相反,整个事情不可能发生在没有主线程干预的背景下。虽然MagicalRecord公开了像MR_Context这样的方法来创建背景NSManagedObjectContext,但是在主线程中执行了保存操作。我创造了GCD的背景环境,然后使用performBlockAndWait这样的:

if ([bContext hasChanges]) { 
      NSError* __autoreleasing error; 
      [bContext save:&error]; 
      [bContext.parentContext saveToPersistentStoreAndWait]; 
     } 

回答

0

我不能说为神奇的记录,因为我从来没有使用过。

但至于可能性,假设您使用过SQLite存储,则存在一些问题:SQLite不允许同时进行多线程访问。根据其开发人员"Threads are evil. Avoid them."

在核心数据术语中,通常意味着您通过后台上下文实例化保存,并且SQL INSERT,DELETE等全部发生在后台,写入磁盘发生在后台等等,但是在发生这种情况时,对持久性存储的所有访问都被锁定。如果主队列试图运行一个查询,或者仅仅是一个对象的错误,那么它必须阻塞,等待保存完成。

因此,至少在一个非常真实的意义上,你不能保证不会影响主线程,除非你能保证主线程根本不会尝试访问存储。

常见的解决方案包括使用显式SQL风格提取的主队列上的被管理对象的字典版本,不一定在主队列上,因为不可变字典是线程安全的,使用从Core Data构建的其他一些自定义结构,但随后不太可能引用它,只是不担心它,如果后台保存相对较短,并且不太可能会打到一个,或者甚至将背景中的保存分解为小块以减少主体的最大时间队列可能会阻塞。尽管如此,请注意最后一个,因为插入成本在SQLite中非线性地增加,例如,插入五个十个对象总共需要比插入五十个对象更长的时间。

我也设法获得一些好的里程数,以便在后台宣布计划立即保存时在近期主线程中抓取任何我认为用户可能想要的东西。