How can I debounce a method call?

前端 未结 13 1524
醉梦人生
醉梦人生 2020-11-30 01:18

I\'m trying to use a UISearchView to query google places. In doing so, on text change calls for my UISearchBar, I\'m making a request to google pla

13条回答
  •  渐次进展
    2020-11-30 01:46

    owenoak's solution works for me. I changed it a little bit to fit my project:

    I created a swift file Dispatcher.swift:

    import Cocoa
    
    // Encapsulate an action so that we can use it with NSTimer.
    class Handler {
    
        let action: ()->()
    
        init(_ action: ()->()) {
            self.action = action
        }
    
        @objc func handle() {
            action()
        }
    
    }
    
    // Creates and returns a new debounced version of the passed function 
    // which will postpone its execution until after delay seconds have elapsed 
    // since the last time it was invoked.
    func debounce(delay: NSTimeInterval, action: ()->()) -> ()->() {
        let handler = Handler(action)
        var timer: NSTimer?
        return {
            if let timer = timer {
                timer.invalidate() // if calling again, invalidate the last timer
            }
            timer = NSTimer(timeInterval: delay, target: handler, selector: "handle", userInfo: nil, repeats: false)
            NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSDefaultRunLoopMode)
            NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSEventTrackingRunLoopMode)
        }
    }
    

    Then I added the following in my UI class:

    class func changed() {
            print("changed")
        }
    let debouncedChanged = debounce(0.5, action: MainWindowController.changed)
    

    The key difference from owenoak's anwer is this line:

    NSRunLoop.currentRunLoop().addTimer(timer!, forMode: NSEventTrackingRunLoopMode)
    

    Without this line, the timer never triggers if the UI loses focus.

提交回复
热议问题