I know there have been I would say similar questions, but none of them fits my case -> see my already tried attempts below.
所以我想做的是制作一个高级搜索栏。因此,每次 searchParam 更改时,我都需要执行代码来检查我的 TableViewItems(数组)是否符合条件 -> 过滤器。
当 smo.例如输入 3 个字符,我的代码检查这个字符串。但这需要一段时间才能获得所有结果。
问题: 当 smo。然后键入第 4 个字符,我想停止之前的执行并开始一个新的字符串 4。
我的尝试:
使用 DispatchWorkItem:
这里的问题是它只改变了一个 bool 值,代码需要 10 秒以上的时间才能识别它改变了。如果我执行
.sync
而不是.async
就可以工作,但它会使应用卡住超过 10 秒使用 DispatchQueue:
无法停止,只能暂停 -> 所以会保留在内存中 -> 会垃圾内存
在每个
for 循环
中检查 bool 值:与 DispatchWorkItem 相同,需要 10 秒以上才能识别更改
当前代码:(不是很重要)
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.stop = true
if people != nil {
if searchText.isEmpty {
searchedPeople = people
self.stop = false
} else {
self.searchedPeople = []
self.tableView.reloadData()
workItem = DispatchWorkItem(qos: .userInitiated, flags: []) {
outter: for i in 0...searchText.count - 1 {
if self.stop { self.stop = false;break outter } //
if i == 0 {
inner: for person in self.people! {
if self.stop { self.stop = false;break outter } //
let name = (person.Vorname != nil ? person.Vorname! + " " : "") + (person.Nachname ?? "")
if name.lowercased().contains(searchText.lowercased()) {
print("Found: \(name), \(searchText), Exact Match")
self.searchedPeople?.append(person);DispatchQueue.main.async { self.tableView.reloadData()}; continue inner
}
}
} else {
let firstP = searchText.prefix(i+1)
let lastP = searchText.suffix(searchText.count - i + 1)
inner2: for person in self.people! {
if self.stop { self.stop = false;break outter } //
let name = (person.Vorname != nil ? person.Vorname! + " " : "") + (person.Nachname ?? "")
if name.lowercased().contains(firstP.lowercased()) && (name.lowercased().contains(lastP.lowercased())) {
print("Found: \(name), \(searchText), First: \(firstP), Last: \(lastP)")
self.searchedPeople?.append(person)
DispatchQueue.main.async { self.tableView.reloadData()}
continue inner2
}
}
}
}
}
//execute
DispatchQueue.async(execute: workItem)
}
}
}
最佳答案
从本质上讲,您的问题是,当您应该检查本地状态时,您却在检查全局状态。假设您正在进行操作“L”,并且您刚刚键入了“e”,因此操作“Le”将开始。这是大致发生的事情:
func updateMyPeepz() {
// At this point, `self.workItem` contains operation 'L'
self.workItem.cancel() // just set isCancelled to true on operation 'L'
self.workItem = DispatchWorkItem { /* bla bla bla */ }
// *now* self.workItem points to operation 'Le'!
}
稍后,在操作“L”的工作项中,您执行以下操作:
if self.workItem.isCancelled { /* do something */ }
不幸的是,此代码在操作“L”中运行,但 self.workItem
现在指向操作“Le”!因此,当操作“L”被取消而操作“Le”没有被取消时,操作“L”会看到 self.workItem
——即操作“Le”——没有被取消。因此,检查始终返回 false
,并且操作“L”实际上从未停止。
当您使用全局 bool 变量时,您会遇到同样的问题,因为它是全局的,并且不会区分应该仍在运行的操作和不应该运行的操作(除了原子性问题之外,您已经如果您不使用信号量保护变量,将要介绍)。
修复方法如下:
func updateMyPeepz() {
var workItem: DispatchWorkItem? = nil // This is a local variable
self.currentWorkItem?.cancel() // Cancel the one that was already running
workItem = DispatchWorkItem { /* bla */ } // Set the *local variable* not the property
self.currentWorkItem = workItem // now we set the property
DispatchQueue.global(qos: whatever).async(execute: workItem) // run it
}
现在,这是关键部分。在你的循环中,像这样检查:
if workItem?.isCancelled ?? false // check local workItem, *not* self.workItem!
// (you can also do workItem!.isCancelled if you want, since we can be sure this is non-nil)
在 workItem 的末尾,将 workItem 设置为 nil
以摆脱保留周期(否则会泄漏):
workItem = nil // not self.workItem! Nil out *our* item, not the property
或者,您可以将 [weak workItem] in
放在 workItem
block 的顶部以防止循环——这样您就不必在结束了,不过你一定要用?? false
而不是 !
因为你总是想假设一个弱变量可以随时变为 nil。
关于ios - swift |强制取消执行代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51506072/