ios - swift |强制取消执行代码

标签 ios swift function

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/

相关文章:

ios - 我正在制作一个可以自行拍摄全景照片的 iOS 应用

ios - 如何更改 Split View Controller 项目的宽度大小(主视图 Controller - 详细 View Controller )?

ios - 容器 View 和传递数据

ios - Cloudkit 的 NSPredicate 匹配字符串

c - 在 C 中传递结构的一部分

ios - Swift - NSIndex forRow inSection Initializer

iOS 高 rebase /绑定(bind)时间

ios - 离开 View Controller 后保留任务

android - Kotlin 顶层函数 vs 对象函数

python - 函数内的函数次数未知