So I have an app that loads movie search results from the web live as the user types. I throttle my search requests so that it only reloads once every 0.3 seconds. (This probably isn't relevant at all, but what the hell). Now my problem is this.
1 - I type in a search term, let's say "Search1". In order to save time, I load up each result's title, year and genre instantly (almost). I keep the poster black, and send an asynchronous request to load the image, because it takes a lot more time. I wait for the image to load.
2 - Before the images load, I then type in another term, let's say "Search2". So I get the text results for "Search2", and maybe some images.
3 - But then the old requests for "Search1" start rolling in, and they replace those of Search2, because they loaded slower. What I get is a combination of old and new images because I couldn't cancel the old requests.
How should I solve this? I need a way to tell the device to stop loading the old images if the user started typing again, and I can't cancel asynchronous requests. How do I fix this?
Code:
The cell throttling stuff
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) }
Here is the code that loads up each cell's info:
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 }
You can just check the indexPath of the cell and see if it's the same or if it's been dequeued and reused for another another row.
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
}
}
}
}
})
For future people stuck with the same issue, I used Alamofire , a networking library that allows you to cancel asynchronous requests. If you use Objective-C then look up AFNetworking. It's the same thing but for Objective-C.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.