cancelPreviousPerformRequests

cancelPreviousPerformRequests

如标题所述,由于某种原因,以下(简化)代码无法正常工作:

extension InputView: {

    func updateTable(text: String) {
            NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(loadPlaces(text:)), object: nil)
          //NSObject.cancelPreviousPerformRequests(withTarget: self)

            self.perform(#selector(loadPlaces(text:)), with: text, afterDelay: 0.5)

            prevSearch = inputField.text!;
        }

    //Private wrapper function
    @objc private func loadPlaces(text: String) {
        print("loading results for: \(text)")
       // locator?.searchTextHasChanged(text: text)
    }
}

每当用户编辑updateTable时,我都会调用UITextField,后者会调用localPlaces,后者会调用查询Google的在线places API(已注释掉)的函数。不幸的是,每次调用updateTable之后,都会调用loadPlaces中的打印行。从我的目视检查来看,似乎实际上是对打印语句的延迟,但是旧的调用不会取消。我尝试查看许多StackOverflow线程,但是找不到Swift 3的更新内容。我打错了吗?

PS。如果我改用注释掉的单参数cancelPreviousPerformRequests。它因某些原因起作用。

编辑:我已经能够在一个单独的项目中复制此错误。因此,我100%确信上面的代码是错误的。如果您想复制此错误,请打开一个新的iOS项目,并将以下代码粘贴到默认的ViewController中:
class InputView: UIView {

    func updateTable(text: String) {
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(loadPlaces(text:)), object: nil)

        self.perform(#selector(loadPlaces(text:)), with: text, afterDelay: 0.5)

    }

    //Private wrapper function
    @objc private func loadPlaces(text: String) {
        print("loading results for: \(text)")
        // locator?.searchTextHasChanged(text: text)
    }
}




class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let input = InputView()

        for i in 0..<200 {
            input.updateTable(text: "Call \(i)")
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

最佳答案

Duncan C的答案中的解释不适用于这种情况。
cancelPreviousPerformRequests(withTarget:selector:object:) 的引用中:

讨论区
具有与aTarget相同的目标,与anArgument相同的参数以及与选择器相同的目标的所有执行请求都被取消。aSelector

所以,当你有这样的一行:

<aTarget>.perform(<aSelector>, with: <anArgument>, afterDelay: someDelay)
您可以使用以下方法取消它:
NSObject.cancelPreviousPerformRequests(withTarget: <aTarget>, selector: <aSelector>, object: <anArgument>)
仅当aTargetaSelector anArgument 都匹配时。

请尝试执行以下操作,然后查看您看到的内容:
class InputView: UIView {

    var lastPerformArgument: NSString? = nil

    func updateTable(text: String) {
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(loadPlaces(text:)), object: lastPerformArgument)

        lastPerformArgument = text as NSString
        self.perform(#selector(loadPlaces(text:)), with: lastPerformArgument, afterDelay: 0.5)

    }

    //Private wrapper function
    @objc private func loadPlaces(text: String) {
        print("loading results for: \(text)")
        // locator?.searchTextHasChanged(text: text)
    }
}

07-27 20:32