Swift:如果函数在 PFQuery 完成之前再次为 运行,如何取消 PFQuery?

Swift: How to cancel a PFQuery if function is run again before PFQuery is finished?

抱歉,我想不出更好的标题方式。

基本上我有一个连接到 Parse 的应用程序。我指定了一个操作,当文本字段更改时(即当用户键入字母时)运行s

在此操作中,我调用 PFQuery 进行解析,然后我要求它找到 ObjectsInBackgroundWithBlock。

问题是,如果用户在此查询完成 运行ning 之前键入另一个字母,那么现在有 2 个查询 运行ning 并且两个查询的结果最终都会填充到 tableView .

所以我的问题很简单,如果用户在第一个 findObjectsInBackgroundWithBlock 完成之前输入另一个字母,我将如何取消第一个字母并 运行 一个新字母?

我尝试在操作开始时插入 PFQuery.cancel(query),但是代码变得混乱,因为当操作 运行 时还没有查询 运行ning ] 是第一次。

我的代码,以防有帮助:

@IBAction func textFieldChanged (sender: AnyObject) {
let query = PFUser.Query()
query!.whereKey("Postcode", containsString: searchField.text)
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
   if let objects = objects {
      for object in objects {
         self.citiesArray.append(object["city"] as! String)
      }
   }
})

非常感谢您的耐心等待!

您可以尝试将这些请求包装在 NSOperation 中并将它们添加到专用的(对于此类搜索请求)NSOperationQueue 并在键入新字符时调用 cancelAllOperations()

NSOperation 的内部 Parse 块中检查 self.cancelled 和 return 如果取消则不执行任何操作。应该工作正常。

更新:

class ViewController: UIViewController {

    @IBOutlet weak var searchField: UITextField!

    var citiesArray = [String]()

    lazy var textRequestQueue: NSOperationQueue = {
        var queue = NSOperationQueue()
        queue.maxConcurrentOperationCount = 1
        queue.qualityOfService = NSQualityOfService.UserInteractive
        return queue
        }()

    @IBAction func textFieldChanged(sender: AnyObject) {
        textRequestQueue.cancelAllOperations()
        let query = PFQuery()
        query.whereKey("Postcode", containsString: searchField.text)
        textRequestQueue.addOperation(TextRequestOperation(query: query, resultBlock: { (objects, error) -> Void in
            if let objects = objects {
                for object in objects {
                    self.citiesArray.append(object["city"] as! String)
                }
            }
        }))
    }

}

class TextRequestOperation: NSOperation {

    typealias ResultBlock = ((result: String)->())

    var _resultBlock: PFArrayResultBlock
    var _query: PFQuery

    init(query: PFQuery, resultBlock: PFArrayResultBlock) {
        self._resultBlock = resultBlock
        self._query = query
    }

    override func main()
    {
        if self.cancelled { return }
        _query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
            if self.cancelled { return }
            self._resultBlock(objects, error)
        }
    }

}

NSOperation 是一种选择。 ReativeCocoa 是另一个选项,如果您知道如何使用它,可以帮助您轻松解决此问题。

然而,最简单(也是最 hackiest)的方法可能是保留搜索的某些状态并使用它仅应用最近的搜索结果。

var mostRecentSearchQuery: String = ""

@IBAction func textFieldChanged (sender: AnyObject) {
var queryString: String?
if let textField: UITextField = sender as? UITextField {
    queryString = textField.text
    self.mostRecentSearchQuery = textField.text
}
let query = PFUser.Query()
query!.whereKey("Postcode", containsString: searchField.text)
query?.findObjectsInBackgroundWithBlock({[weak self] (objects, error) -> Void in
   if let objects = objects where queryString == self?.mostRecentSearchQuery {
      for object in objects {
         self.citiesArray.append(object["city"] as! String)
      }
   }
})

如果块使用了最近键入的文本,这只会更新您的结果。

ps。我假设传递给方法的发件人是文本已更改的 textField。