Swift - 加载搜索结果时出现并发问题。我加载图像,发送请求,但请求为时已晚
Swift - Concurrency issue when loading search result. I load the images, send the requests, but the requests are too late
所以我有一个应用程序可以在用户键入时从网络实时加载电影搜索结果。我限制了搜索请求,使其每 0.3 秒仅重新加载一次。 (这可能根本不相关,但到底是什么)。现在我的问题是这个。
1 - 我输入搜索词,比方说 "Search1"。为了节省时间,我会立即(几乎)加载每个结果的标题、年份和类型。我将海报保持黑色,并发送一个异步请求来加载图像,因为这会花费更多时间。我等待图像加载。
2 - 在图像加载之前,我输入另一个词,比方说 "Search2"。所以我得到了 "Search2" 的文本结果,也许还有一些图片。
3 - 但随后 "Search1" 的旧请求开始涌入,它们取代了 Search2 的请求,因为它们加载速度较慢。我得到的是新旧图像的组合,因为我无法取消旧请求。
我该如何解决?如果用户再次开始输入,我需要一种方法来告诉设备停止加载旧图像,而且我无法取消异步请求。我该如何解决这个问题?
代码:
细胞节流
func updateSearchResultsForSearchController(searchController: UISearchController) {
// to limit network activity, reload 0.3 of a second after last key press.
NSObject.cancelPreviousPerformRequestsWithTarget(self, selector: "reload:", object: searchController)
if (!UIApplication.sharedApplication().networkActivityIndicatorVisible) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
self.tableView.reloadData()
}
self.performSelector("reload:", withObject: searchController, afterDelay: 0.3)
}
这是加载每个单元格信息的代码:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")! as! CustomCell
//Safe-Guard. This shouldn't be needed if I understood what I was doing
if (indexPath.row < matchingItems.count) {
cell.entry = matchingItems[indexPath.row] //404
/*
.
.
omitted code that loads up text info (title, year, etc.)
.
.
*/
//Poster
cell.poster.image = nil
if let imagePath = matchingItems[indexPath.row]["poster_path"] as? String {
//Sessions and Stuff for request
let url = NSURL(string: "http://image.tmdb.org/t/p/w185" + imagePath)
let urlRequest = NSURLRequest(URL: url!)
let session = NSURLSession.sharedSession()
//Asynchronous Code:
let dataTask = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) -> Void in
if let poster = UIImage(data: data!) {
//I want to stop this piece from running if the user starts typing again:
dispatch_async(dispatch_get_main_queue()) {
//Animate the poster in
cell.poster.alpha = 0.0 // hide it
cell.poster.image = poster // set it
UIView.animateWithDuration(1.0) {
cell.poster.alpha = 1.0 // fade it in
}
}
}
})
dataTask.resume()
} else {
//Just use placeholder if no image exists
cell.poster.image = UIImage(named: "Placeholder.jpg")
}
}
return cell
}
您可以只检查单元格的 indexPath,看看它是否相同,或者它是否已出列并重新用于另一行。
let dataTask = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) -> Void in
if let poster = UIImage(data: data!) {
//I want to stop this piece from running if the user starts typing again:
dispatch_async(dispatch_get_main_queue()) {
//Animate the poster in
if tableView.indexPathForCell(cell) == indexPath {
cell.poster.alpha = 0.0 // hide it
cell.poster.image = poster // set it
UIView.animateWithDuration(1.0) {
cell.poster.alpha = 1.0 // fade it in
}
}
}
}
})
为了将来遇到同样问题的人,我使用了 Alamofire,这是一个允许您取消异步请求的网络库。如果您使用 Objective-C 然后查找 AFNetworking。这是同一件事,但 Objective-C.
所以我有一个应用程序可以在用户键入时从网络实时加载电影搜索结果。我限制了搜索请求,使其每 0.3 秒仅重新加载一次。 (这可能根本不相关,但到底是什么)。现在我的问题是这个。
1 - 我输入搜索词,比方说 "Search1"。为了节省时间,我会立即(几乎)加载每个结果的标题、年份和类型。我将海报保持黑色,并发送一个异步请求来加载图像,因为这会花费更多时间。我等待图像加载。
2 - 在图像加载之前,我输入另一个词,比方说 "Search2"。所以我得到了 "Search2" 的文本结果,也许还有一些图片。
3 - 但随后 "Search1" 的旧请求开始涌入,它们取代了 Search2 的请求,因为它们加载速度较慢。我得到的是新旧图像的组合,因为我无法取消旧请求。
我该如何解决?如果用户再次开始输入,我需要一种方法来告诉设备停止加载旧图像,而且我无法取消异步请求。我该如何解决这个问题?
代码:
细胞节流
func updateSearchResultsForSearchController(searchController: UISearchController) {
// to limit network activity, reload 0.3 of a second after last key press. NSObject.cancelPreviousPerformRequestsWithTarget(self, selector: "reload:", object: searchController) if (!UIApplication.sharedApplication().networkActivityIndicatorVisible) { UIApplication.sharedApplication().networkActivityIndicatorVisible = true self.tableView.reloadData() } self.performSelector("reload:", withObject: searchController, afterDelay: 0.3) }
这是加载每个单元格信息的代码:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("cell")! as! CustomCell //Safe-Guard. This shouldn't be needed if I understood what I was doing if (indexPath.row < matchingItems.count) { cell.entry = matchingItems[indexPath.row] //404 /* . . omitted code that loads up text info (title, year, etc.) . . */ //Poster cell.poster.image = nil if let imagePath = matchingItems[indexPath.row]["poster_path"] as? String { //Sessions and Stuff for request let url = NSURL(string: "http://image.tmdb.org/t/p/w185" + imagePath) let urlRequest = NSURLRequest(URL: url!) let session = NSURLSession.sharedSession() //Asynchronous Code: let dataTask = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) -> Void in if let poster = UIImage(data: data!) { //I want to stop this piece from running if the user starts typing again: dispatch_async(dispatch_get_main_queue()) { //Animate the poster in cell.poster.alpha = 0.0 // hide it cell.poster.image = poster // set it UIView.animateWithDuration(1.0) { cell.poster.alpha = 1.0 // fade it in } } } }) dataTask.resume() } else { //Just use placeholder if no image exists cell.poster.image = UIImage(named: "Placeholder.jpg") } } return cell }
您可以只检查单元格的 indexPath,看看它是否相同,或者它是否已出列并重新用于另一行。
let dataTask = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) -> Void in
if let poster = UIImage(data: data!) {
//I want to stop this piece from running if the user starts typing again:
dispatch_async(dispatch_get_main_queue()) {
//Animate the poster in
if tableView.indexPathForCell(cell) == indexPath {
cell.poster.alpha = 0.0 // hide it
cell.poster.image = poster // set it
UIView.animateWithDuration(1.0) {
cell.poster.alpha = 1.0 // fade it in
}
}
}
}
})
为了将来遇到同样问题的人,我使用了 Alamofire,这是一个允许您取消异步请求的网络库。如果您使用 Objective-C 然后查找 AFNetworking。这是同一件事,但 Objective-C.