Swift 4解决方案,外加一些一般性注释:
这些都是合理的方法,但是如果您想要示范性的自动搜索行为,则确实需要两个单独的计时器或调度。
理想的行为是:1)定期触发自动搜索,但2)不太频繁(由于服务器负载,蜂窝带宽以及可能导致UI停顿的可能性),并且3)暂停输入后迅速触发用户的输入。
您可以通过一个长期计时器来实现此功能,该计时器会在编辑开始时立即触发(我建议2秒),并且无论以后的活动如何都可以运行,再加上一个短期计时器(约0.75秒),每个计时器都会重置一次更改。任何一个计时器到期都会触发自动搜索并重置两个计时器。
最终结果是连续键入会每隔很长时间自动产生一次自动搜索,但是可以保证暂停会在短时间内触发自动搜索。
您可以使用下面的AutosearchTimer类非常简单地实现此行为。使用方法如下:
lazy var timer = AutosearchTimer { [weak self] in self?.performSearch() }
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
timer.activate()
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
performSearch()
}
func performSearch() {
timer.cancel()
}
AutosearchTimer在释放时会处理自己的清理操作,因此您无需在自己的代码中担心这一点。但是,不要给计时器强烈的自我参考,否则您将创建一个参考周期。
下面的实现使用计时器,但是您可以根据需要在调度操作方面重铸它。
class AutosearchTimer {
let shortInterval: TimeInterval
let longInterval: TimeInterval
let callback: () -> Void
var shortTimer: Timer?
var longTimer: Timer?
enum Const {
static let longAutosearchDelay: TimeInterval = 2.0
static let shortAutosearchDelay: TimeInterval = 0.75
}
init(short: TimeInterval = Const.shortAutosearchDelay,
long: TimeInterval = Const.longAutosearchDelay,
callback: @escaping () -> Void)
{
shortInterval = short
longInterval = long
self.callback = callback
}
func activate() {
shortTimer?.invalidate()
shortTimer = Timer.scheduledTimer(withTimeInterval: shortInterval, repeats: false)
{ [weak self] _ in self?.fire() }
if longTimer == nil {
longTimer = Timer.scheduledTimer(withTimeInterval: longInterval, repeats: false)
{ [weak self] _ in self?.fire() }
}
}
func cancel() {
shortTimer?.invalidate()
longTimer?.invalidate()
shortTimer = nil; longTimer = nil
}
private func fire() {
cancel()
callback()
}
}