即使在ARC下,在GCD中使用Realm时我们是否必须使用显式自动释放池

时间:2015-12-04 08:43:59

标签: ios realm

在Realm的医生中说:

使用Grand Central Dispatch访问Realm时,您可能也会遇到此问题。当一个Realm在调度队列的自动释放池中结束时会发生这种情况,因为这些池在执行代码后可能不会耗尽一段时间。在取消分配RLMRealm对象之前,不能重用Realm文件中的数据的中间版本。 要避免此问题,您应该在从调度队列访问Realm时使用显式自动释放池。

这是否意味着即使在ARC下,我们每次都必须在GCD中使用显式自动释放池?有人可以发布代码示例吗?这有点重要,但官方文档并没有那么强调

2 个答案:

答案 0 :(得分:2)

每次都不必使用显式自动释放池。它与您执行大量并发事务的情况更相关,并且很容易遇到跟踪许多即时版本的风险。或者,当您想要确保通过释放所有打开的访问者来关闭应用程序生命周期中的Realm文件时。

在这一点上,文档更多地被理解为了解技术限制并暗示如何在遇到类似问题时解决问题,而不是一般的最佳实践。当然,你总能做到这一点并不一定会伤到你(如果你有一把锤子,一切看起来像钉子。),但你不一定要这样做。

每个人都不需要这种确切含义的额外复杂性。了解显式自动释放池需要更深入地了解ARC,这不是一般要求。如果您有想法,如何以更好的方式解决这些问题,那么您的反馈非常受欢迎。

Using a Realm Across Threads部分给出了一个示例,在后台队列中插入了一百万个对象:

dispatch_async(queue) {
  autoreleasepool {
    // Get realm and table instances for this thread
    let realm = try! Realm()

    // Break up the writing blocks into smaller portions
    // by starting a new transaction
    for idx1 in 0..<1000 {
      realm.beginWrite()

      // Add row via dictionary. Property order is ignored.
      for idx2 in 0..<1000 {
        realm.create(Person.self, value: [
          "name": "\(idx1)",
          "birthdate": NSDate(timeIntervalSince1970: NSTimeInterval(idx2))
        ])
      }

      // Commit the write transaction
      // to make this data available to other threads
      try! realm.commitWrite()
    }
  }
}

在一个单独的自动释放池中创建对象创建通常是有意义的,因为当对象释放发生时你无法用ARC真正预测,所以你有一个明确的时间点,当它们最新发生时,这使你的程序更明确为你和其他人理解

答案 1 :(得分:0)

  

要避免此问题,在从调度队列访问Realm时应使用显式自动释放池。

     

这是否意味着即使在ARC下,我们每次都必须在GCD中使用显式自动释放池?

我不同意当前接受的答案,在任何后台线程(尤其是线程池,如GCD)上,您应该在不再需要时尽快强制关闭Realm实例,以避免版本保留。在iOS中,autoreleasepool { ... }可以强制关闭Realm实例。

因此对于后台线程, 通常建议始终使用显式自动释放池。

dispatch_async(queue) {
  autoreleasepool {
    let realm = try! Realm()
    //...
  }
}

最好尽可能减少从后台线程提交的事务数量,因此您应该尝试使用1个事务而不是N.

// Break up the writing blocks into smaller portions
// by starting a new transaction
realm.beginWrite()
for idx1 in 0..<1000 {
  // Add row via dictionary. Property order is ignored.
  for idx2 in 0..<1000 {
    realm.create(Person.self, value: [
      "name": "\(idx1)",
      "birthdate": NSDate(timeIntervalSince1970: NSTimeInterval(idx2))
    ])
  }
}
// Commit the write transaction
// to make this data available to other threads
try! realm.commitWrite()