Giải pháp Swift 4, cùng với một số nhận xét chung:
Đây là tất cả các cách tiếp cận hợp lý, nhưng nếu bạn muốn hành vi tự động tìm kiếm mẫu mực, bạn thực sự cần hai bộ hẹn giờ hoặc công văn riêng biệt.
Hành vi lý tưởng là 1) tự động tìm kiếm được kích hoạt định kỳ, nhưng 2) không quá thường xuyên (do tải máy chủ, băng thông di động và khả năng gây ra lỗi giao diện người dùng) và 3) tính năng này sẽ kích hoạt nhanh chóng ngay khi có tạm dừng của người dùng.
Bạn có thể đạt được hành vi này với một bộ hẹn giờ dài hạn hơn được kích hoạt ngay khi bắt đầu chỉnh sửa (tôi đề xuất là 2 giây) và được phép chạy bất kể hoạt động sau đó, cộng với một bộ hẹn giờ ngắn hạn (~ 0,75 giây) được đặt lại vào mỗi thay đổi. Việc hết hạn của một trong hai bộ hẹn giờ sẽ kích hoạt tự động tìm kiếm và đặt lại cả hai bộ hẹn giờ.
Hiệu quả thực sự là việc nhập liên tục mang lại tự động tìm kiếm sau mỗi giây dài, nhưng thời gian tạm dừng được đảm bảo sẽ kích hoạt tự động tìm kiếm trong khoảng thời gian ngắn.
Bạn có thể thực hiện hành vi này rất đơn giản với lớp AutosearchTimer bên dưới. Đây là cách sử dụng nó:
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 xử lý quá trình dọn dẹp của chính nó khi được giải phóng, vì vậy không cần phải lo lắng về điều đó trong mã của riêng bạn. Nhưng đừng cung cấp cho bộ đếm thời gian một tham chiếu mạnh về chính nó, nếu không bạn sẽ tạo ra một chu kỳ tham chiếu.
Việc triển khai bên dưới sử dụng bộ hẹn giờ, nhưng bạn có thể chỉnh sửa lại nó trong điều kiện hoạt động điều phối nếu muốn.
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()
}
}