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

时间:2015-08-03 13:42:08

标签: ios swift parse-platform pfquery

道歉,我想不出一个更好的方法来标题。

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

在这个动作中我正在调用PFQuery来解析,然后我要求findObjectsInBackgroundWithBlock。

问题是,如果用户在此查询完成运行之前键入另一个字母,则现在正在运行2个查询,并且两个结果最终填充tableView。

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

我已尝试在操作开始时插入PFQuery.cancel(查询),但代码感到困惑,因为当该操作第一次运行时尚未运行查询。

我的代码,包含它可能会有所帮助:

@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)
      }
   }
})

非常感谢您的耐心等待!

2 个答案:

答案 0 :(得分:4)

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

NSOperation的内部Parse块中检查self.cancelled,如果取消则不返回任何内容。应该工作正常。

<强>更新

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)
        }
    }

}

答案 1 :(得分:2)

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

然而,最简单的方法(也是最黑客的)可能是保留一些搜索状态并使用它来仅应用最新的搜索结果。

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,文本已经改变了。