从 backgroundThread 合并到 mainThread 上下文:删除顺序随机所以崩溃 NSTableView
Merging from backgroundThread to mainThread context: delete order random so crashes NSTableView
我在删除后台线程上的多个对象时遇到了问题:
func delete(hierarchy: Hierarchy) throws {
// let backgroundThread = self.mainThread
let hierarchies = try self.hierarchies.reloadFrom(context: backgroundThread)
let hierarchy = try hierarchy.reloadFrom(context: backgroundThread)
let hierarchyModel = hierarchy.model!
// .. doing some checks ..
backgroundThread.performAndWait {
backgroundThread.delete(rootFile)
backgroundThread.delete(hierarchyModel)
for (index, model) in hierarchies.model!.hierarchies!.array.enumerated() {
let hierarchyModel = model as! HierarchyModel
hierarchyModel.position = Int32(index)
}
}
try backgroundThread.save()
}
然后循环:
func delete(hierarchies: [Hierarchy]) {
do {
for hierarchy in hierarchies {
try modelController.delete(hierarchy: hierarchy)
}
} catch {
NotificationCenter.default.post(FatalErrorNotification(error: error))
}
}
在保存时,通常的 NSFetchedResultsController 会调用它的委托。请注意,他在 mainThread 上工作。
public func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
print(indexPath, newIndexPath)
switch type {
case .insert:
// ...
case .delete:
tableView.removeRows(at: IndexSet(integer: indexPath!.item), withAnimation: .slideRight)
case .update:
// ...
case .move:
// ...
}
}
我使用 mainThread.automaticallyMergeChangesFromParent
获取从 backgroundThread 到 mainThread 的更改。到目前为止,这对我来说效果很好。
我的问题是在合并过程中会发生这样的事情:
# Merging from background thread, delete order crashes.
Optional([0, 0]) nil
Optional([0, 1]) nil
Optional([0, 2]) nil
在 fetchedResultsController 委托调用崩溃之前。它在第三次调用时崩溃,只剩下 [0, 0] 行要删除。所以它使应用程序崩溃。
如果我在 mainThread 上执行删除操作,则删除操作一个接一个地完成:
# On mainThread: delete order works.
Optional([0, 0]) nil
Optional([0, 2]) Optional([0, 1])
Optional([0, 1]) Optional([0, 0])
going to end updates.
endUpdates
beginUpdates
Optional([0, 0]) nil
Optional([0, 1]) Optional([0, 0])
going to end updates.
endUpdates
beginUpdates
Optional([0, 0]) nil
going to end updates.
endUpdates
不会崩溃。我尝试了什么:
- 仅在所有三个删除之后而不是在每个删除之后调用保存。
- 颠倒删除顺序。
- 更改合并策略(生气)
- 在 backgroundThread.performAndWait { ... }
中包装了整个删除功能
- 试图找到一种方法,使更改在删除之前转到 mainThread。
再收集一些删除命令:
# On background thread: lucky.
beginUpdates
Optional([0, 2]) nil
Optional([0, 1]) nil
Optional([0, 0]) nil
going to end updates.
endUpdates
# On background thread: lucky again.
beginUpdates
Optional([0, 2]) nil
Optional([0, 1]) nil
Optional([0, 0]) nil
going to end updates.
endUpdates
# On background thread: unlucky again.
Optional([0, 1]) nil
Optional([0, 0]) nil
Optional([0, 2]) nil
# On background thread: unlucky again.
Optional([0, 0]) nil
Optional([0, 1]) nil
Optional([0, 2]) nil
# On background thread: unlucky on 2nd delete already.
beginUpdates
Optional([0, 1]) nil
Optional([0, 2]) nil
我希望有人能帮我解决这个问题。真的很感激,我卡住了。
//
// NSFetchedResultsControllerDelegate
//
public func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
print("beginUpdates")
tableView.beginUpdates()
}
public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
print("going to end updates.")
tableView.endUpdates()
print("endUpdates")
}
我想我找到了问题所在。您不能在后台线程上删除对象,然后重新排序,然后期望删除以正确的顺序到达主线程。
我在删除后台线程上的多个对象时遇到了问题:
func delete(hierarchy: Hierarchy) throws {
// let backgroundThread = self.mainThread
let hierarchies = try self.hierarchies.reloadFrom(context: backgroundThread)
let hierarchy = try hierarchy.reloadFrom(context: backgroundThread)
let hierarchyModel = hierarchy.model!
// .. doing some checks ..
backgroundThread.performAndWait {
backgroundThread.delete(rootFile)
backgroundThread.delete(hierarchyModel)
for (index, model) in hierarchies.model!.hierarchies!.array.enumerated() {
let hierarchyModel = model as! HierarchyModel
hierarchyModel.position = Int32(index)
}
}
try backgroundThread.save()
}
然后循环:
func delete(hierarchies: [Hierarchy]) {
do {
for hierarchy in hierarchies {
try modelController.delete(hierarchy: hierarchy)
}
} catch {
NotificationCenter.default.post(FatalErrorNotification(error: error))
}
}
在保存时,通常的 NSFetchedResultsController 会调用它的委托。请注意,他在 mainThread 上工作。
public func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
print(indexPath, newIndexPath)
switch type {
case .insert:
// ...
case .delete:
tableView.removeRows(at: IndexSet(integer: indexPath!.item), withAnimation: .slideRight)
case .update:
// ...
case .move:
// ...
}
}
我使用 mainThread.automaticallyMergeChangesFromParent
获取从 backgroundThread 到 mainThread 的更改。到目前为止,这对我来说效果很好。
我的问题是在合并过程中会发生这样的事情:
# Merging from background thread, delete order crashes.
Optional([0, 0]) nil
Optional([0, 1]) nil
Optional([0, 2]) nil
在 fetchedResultsController 委托调用崩溃之前。它在第三次调用时崩溃,只剩下 [0, 0] 行要删除。所以它使应用程序崩溃。
如果我在 mainThread 上执行删除操作,则删除操作一个接一个地完成:
# On mainThread: delete order works.
Optional([0, 0]) nil
Optional([0, 2]) Optional([0, 1])
Optional([0, 1]) Optional([0, 0])
going to end updates.
endUpdates
beginUpdates
Optional([0, 0]) nil
Optional([0, 1]) Optional([0, 0])
going to end updates.
endUpdates
beginUpdates
Optional([0, 0]) nil
going to end updates.
endUpdates
不会崩溃。我尝试了什么:
- 仅在所有三个删除之后而不是在每个删除之后调用保存。
- 颠倒删除顺序。
- 更改合并策略(生气)
- 在 backgroundThread.performAndWait { ... } 中包装了整个删除功能
- 试图找到一种方法,使更改在删除之前转到 mainThread。
再收集一些删除命令:
# On background thread: lucky.
beginUpdates
Optional([0, 2]) nil
Optional([0, 1]) nil
Optional([0, 0]) nil
going to end updates.
endUpdates
# On background thread: lucky again.
beginUpdates
Optional([0, 2]) nil
Optional([0, 1]) nil
Optional([0, 0]) nil
going to end updates.
endUpdates
# On background thread: unlucky again.
Optional([0, 1]) nil
Optional([0, 0]) nil
Optional([0, 2]) nil
# On background thread: unlucky again.
Optional([0, 0]) nil
Optional([0, 1]) nil
Optional([0, 2]) nil
# On background thread: unlucky on 2nd delete already.
beginUpdates
Optional([0, 1]) nil
Optional([0, 2]) nil
我希望有人能帮我解决这个问题。真的很感激,我卡住了。
//
// NSFetchedResultsControllerDelegate
//
public func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
print("beginUpdates")
tableView.beginUpdates()
}
public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
print("going to end updates.")
tableView.endUpdates()
print("endUpdates")
}
我想我找到了问题所在。您不能在后台线程上删除对象,然后重新排序,然后期望删除以正确的顺序到达主线程。