【发布时间】:2022-01-03 01:54:37
【问题描述】:
我在将 UndoManager / NSUndoManager 用于异步或长时间运行的任务时遇到问题。我有一个可行的解决方案,但非常复杂——对于一个相当常见的问题来说,这远远超过了合理的解决方案。我会将其发布为答案,并希望有更好的答案。
问题一:
我的可撤消任务未在当前运行循环中完成。这样的任务可以是一个带有异步调用回调的简短操作。它也可以是一个长时间运行的操作,我可能会显示一个进度指示器,甚至提供取消选项。
问题 2:
我的可撤消任务可能会失败或被取消。或者更糟的是,重做任务可能会失败。示例:我移动了一个文件,撤消后我发现该文件已从新位置消失。我不应该将重做任务放回堆栈。
想法 1:
我可以在任务完成时进行撤消/重做注册。无法撤消尚未完成、已取消或已失败的操作。使用此设置,我无法正确配对操作及其撤消操作:重做不起作用。示例:用户要求复制文件。在复制操作结束时,我将操作注册到 UndoManager。用户选择撤消。我再次等到操作完成后向 UndoManager 注册。现在UndoManager并不知道刚刚完成的文件删除实际上是对前面复制操作的逆操作。它不是为用户提供重做副本的选项,而是提供撤消删除的选项
想法 2:
禁用自动撤消分组。我看不到如何通过长时间运行的操作来做到这一点。我想为大多数其他任务自动分组。
我无法使用带有 asnyc 回调的简单操作来实现它。此抛出:“endUndoGrouping 调用没有匹配的开始”
let assets = PHAsset.fetchAssets(in: album, options: nil)
let parent = PHCollectionList.fetchCollectionListsContaining(album, options: nil).firstObject
if let undoManager = undoManager {
undoManager.groupsByEvent = false
undoManager.beginUndoGrouping()
let isUndoManagerOperation = undoManager.isUndoing || undoManager.isRedoing
let targetSelf = Controller.self as AnyObject
undoManager.registerUndo(withTarget: targetSelf) { [weak undoManager] targetSelf in
Controller.createAlbum(for: assets, title: album.localizedTitle, parent: parent, with: undoManager, completionHandler: nil)
}
if !isUndoManagerOperation {
undoManager.setActionName(NSLocalizedString("Delete Album", comment: "Undoable action: Delete Album"))
}
}
PHPhotoLibrary.shared().performChanges {
PHAssetCollectionChangeRequest.deleteAssetCollections(NSArray.init(object: album))
} completionHandler: { (success, error) in
DispatchQueue.main.async {
undoManager?.endUndoGrouping()
undoManager?.groupsByEvent = true
}
}
【问题讨论】:
标签: swift cocoa objective-c-blocks nsundomanager