gpt4 book ai didi

swift - 在后台线程上写入后,Realm 通知何时传递到主线程?

转载 作者:搜寻专家 更新时间:2023-10-31 19:32:31 24 4
gpt4 key购买 nike

我看到了不应该发生或极有可能发生的崩溃,而文档只是不够清楚地说明了原因。

更新:

虽然我不同意下面要求我将其分成多个 SO 问题的评论,但如果有人可以专注于这个问题,我认为这会有很大帮助:

通知何时传递到主线程?主线程上的结果是否可能与之前的运行循环中的结果不同,但尚未通知差异?

如果这个问题的答案是是的,结果可能与以前的运行循环不同而没有通知,那么我认为将其写入文档的某个地方是至关重要的。

后台写入

首先,我认为回顾一下我已经为写入所做的工作很重要。我所有的写入都是通过一个基本上看起来像这样的方法执行的(除了错误处理):

func write(block: @escaping (Realm) -> ()) {
somePrivateBackgroundSerialQueue.async {
autoreleasepool {
let realm = try! Realm()
realm.refresh()
try? realm.write { block(realm) }
}
}
}

这里没有什么疯狂的,在你这边有很好的记录。

通知和表格 View

我这里的主要问题是,什么时候从后台线程写入的通知会传送到主线程?我有一个由 Realm 结果支持的复杂 TableView (多个部分,每 5 行有一个广告)。我的主要数据源如下所示:

enum StoryRow {
case story(Story) // Story is a RealmSwift.Object subclass
case ad(Int)
}

class StorySection {
let stories: Results<Story>

var numberOfRows: Int {
let count = stories.count
return count + numberOfAds(before: count)
}

func row(at index: Int) -> StoryRow {
if isAdRow(at: index) {
return .ad(index)
} else {
let storyIndex = index - numberOfAds(before: index)
return .story(stories[storyIndex])
}
}
}

var sections: [StorySection]

... sections[indexPath.section].row(at: indexPath.row) ...

在构建我的部分数组之前,我获取 Realm 结果并根据特定屏幕的故事类型过滤它们,对它们进行排序以便它们按照其部分的正确顺序,然后通过传入 results.filter(...date query...) 到部分构造函数。最后,我 results.observe(...) 主要结果对象(不是传递到该部分的任何结果)并在调用通知处理程序时重新加载 TableView 。我没有费心去观察这些部分中的结果,因为如果这些结果中的任何一个发生变化,那么父级也必须发生变化,并且它应该触发一个变化通知。

当广告被填充或未填充时,广告位有回调,而不是调用 tableView.reloadData() 我正在做类似的事情:

guard tableView.indexPathsForVisibleRows?.contains(indexPath) == true else { return }
tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()

问题是,我很少看到在访问 Realm 结果时索引越界或无效的 TableView 更新导致崩溃。

问题

  1. 是否有可能在传递任何通知之前在主线程上更改了 Realm ?
  2. reloadData() 之外的 TableView 更新是否应该简单地不在 Realm 通知 block 之外的任何地方使用?
  3. 我还缺少其他重要信息吗?

最佳答案

在您的代码片段或对您正在做的事情的描述中,没有任何内容让我觉得明显是错误的。有一个单独的回调机制来更新独立于 Realm 更改通知的特定插槽有很多与时间相关的错误的可能性,但是由于您在重新加载行之前明确检查 indexPath 是否可见,我希望最坏情况下表现为重新加载错误的行而不是崩溃。


预期的行为是刷新 Realm 并传递通知是一个原子操作:任何导致读取版本前进的操作都会在返回之前传递所有通知。在简单的情况下,这意味着如果没有首先触发关联的通知,您将永远看不到新数据。但是,对此有一些注意事项:

嵌套通知传递无法正常工作,因此从通知 block 中开始写入事务可能会导致通知被跳过(仅仅调用 refresh() 不会导致这种情况,因为它是只是通知中的空操作)。如果您在后台线程上执行所有写入操作,则不应执行此操作。

如果您有多个 通知 block ,那么很明显,从第一个通知 block 调用的任何内容都将在第二个通知 block 有机会执行操作和调用 tableView 之前运行。 reloadData() 可能会导致通知 block 中发生很多事情。如果这是问题的根源,您会希望看到异常被抛出,并带有来自通知 block 内的堆栈跟踪。

关于swift - 在后台线程上写入后,Realm 通知何时传递到主线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47194597/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com