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。
抱歉,我想不出更好的标题方式。
基本上我有一个连接到 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。