Reusable TableViewCell loads an old image - ios

I have a dynamic tableview that can be searched through with a search box, and if I load an image in a cell in the background and the search text changes, the object in the cell may also change, and sometimes an old image that was loading in the background will finish and display when it shouldn't. Not every image is loaded in the same way, but this is the method that causes the problem:
[self.CarImage sd_setImageWithURL:imageURL
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageurl){
[self.CarImage setAlpha:0.0];
[UIImageView animateWithDuration:.5 animations:^{
[self.CarImage setAlpha:1.0];
}];
}];
Any ideas would be appreciated

You need to do two things here
1) in prepareforresue method Cancel current downloading request
2) in prepareforresue method set image to nil
Hope this will fix your issue

Here the issue is, image is loaded from url after you have already reused the cell. You can store the url of the image, each and everytime the cell being reused the url of the images should be stored inside the custom cell class. Then inside the completion block check that the loaded image url and the stored image url are same or not using isEqual: method of NSURL. If they are same then everything is ok, cell is not being reused, otherwise the cell is been used for another row, then just dont set the image.
self.carImgUrl = imageURL;//here carImgUrl is a property which you gonna set everytime when the cell is being reused.
[self.CarImage sd_setImageWithURL:imageURL
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageurl){
if([imageurl isEqual:self.carImgUrl])
{
[self.CarImage setAlpha:0.0];
[UIImageView animateWithDuration:.5 animations:^{
[self.CarImage setAlpha:1.0];
}];
}
}];

Related

Dynamically modifying the height of cells in a UICollectionViewCell in Objective C

I need to make a Pinterest style newsfeed. I have created a collection view with 2 columns. I am downloading the photos async in cellForItemAtIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {
TFNewsObject *obj = [self.sortedDataSource objectAtIndex:indexPath.row];
[imageView sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRefreshCached
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
obj.tfImage = image;
}];
return cell;
}
The problem is that I need to set the size of the cell in heightForItemAtIndexPath and there the image has not been downloaded yet because it did not enter cellForItemAtIndexPath yet. I am setting a fixed size of 100 for the height.
I need to somehow trigger heightForItemAtIndexPath after I've downloaded the image in cellforItemAtIndexPath.
Another thing that I've tried is downloading the image in heightForItemAtIndexPath synchronous and calculating the height after the image downloaded. In that manner it displays correctly with each cell with a different height depending on the image, but it takes forever to load all the images.
Is there a way to modify the cell's height after I've downloaded the image? Thanks!
Try this
[imageView sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRefreshCached
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
obj.tfImage = image;
collectionView .reloadItems(at: [indexPath])
}];
In -setImageWithURLRequest:..., when the image loads it in a hash table so you should then call -reloadItemsAtIndexPaths: with the current image path. This will reload the cell and thus cause the CollectionView to check what size the cell should be.
Another solution that you can try is to invalidate the collection view layout when the image is downloaded.
- (UICollectionViewCell *)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {
TFNewsObject *obj = [self.sortedDataSource objectAtIndex:indexPath.row];
[imageView sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRefreshCached
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
[self.collectionView.collectionViewLayout invalidateLayout];
}];
return cell;
}
After this return a appropriate size in the delegate method:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return /* size */;
}
I got into similar problem while i developed something similar to pinterest layout.
Even we had a lag while downloading images asynchronously and once the download is done refreshing cell by cell will blow away the user and will lead to UI jerks.
The solution which i could suggest is,
For example when the post is created with the image, Calculate the size (width and height) of the image and save it in the DB. So the size of the image is available before the image is downloaded or cached and we could scale the cell to the height of the image and display a default image and when the actual image is cached or downloaded it would silently replace the default image without any UI jerks.
If you are using services like cloudinary then you can avoid the pain of storing the image size (height and width). The cloudinary api will give you the height and width of the image.

Loading images of "Next" TableView Cell Asynchronously

So I am using SDWebImage to load images into the cells.
I want to preload images of the next few cells so that when the user scrolls, the image is already loaded.
Whats the ideal way to do this.
Current code -->
[cell.BGImage sd_setImageWithURL:[NSURL URLWithString:section.imageURL] placeholderImage:[UIImage imageNamed:#"PlaceholderF"]];
Ensuring that the current displayed image is kept at priority loading.
Any suggestions?
You can use SDWebImageDownloader method to download image before your cell load or in other controller. So it will cache image and when your cell load it will show immediately.
[[SDWebImageDownloader sharedDownloader]downloadImageWithURL:nil options:SDWebImageDownloaderContinueInBackground progress:^(NSInteger receivedSize, NSInteger expectedSize) {
} completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
}];
and you can set download image priority in LIFO manner using below code.
[[SDWebImageManager sharedManager].imageDownloader setExecutionOrder:SDWebImageDownloaderLIFOExecutionOrder];
Maybe this will help you.

Some problems with SDWebImage

When I used the method load image, after the image gets downloaded, it does not show until I select or scroll the cell, but if I don't set the placeholderImage to nil, it works well. I don't know what's wrong with. Here's my code:
[cell.imageView sd_setImageWithURL:(my url) placeholderImage:nil];
Some problems with SDWebImage
It's weird, but you can try [cell setNeedsLayout]; after you set the image to reload all the cell views.
I guess you have all the calls inside tableView:cellForRowAtIndexPath:
use completion block to change the image view.
[myImage sd_setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:IMG_PLACEHOLDER] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {}];
use this in your project and try.
Maybe you can use another method to do this, as an example:
[_theImageView sd_setImageWithURL:[NSURL URLWithString:_imageUrl]]

iOS SDWebImage Cross Fade Effect UITableViewCell

This is how i am successfully using SDWebImageManager to download the images:
- (void) downloadThumbnails:(NSURL *) finalUrl
{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:finalUrl
options:0
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
if (image)
{
self.thumbnailURL = [finalUrl absoluteString];
}
}];
}
- (UIImage*)thumbnail {
if (!self.thumbnailURL) return nil;
return [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:self.thumbnailURL];
}
How can i modify to have a cross fade effect? Cross Fade Effect is the one that makes the image showing transition slowly just like the TechCrunch iOS App. Thanks!
UPDATE: If i can do anything else to have cross fade effect (other than SDWebImage) in uitableview cell than you can write it in the answer.
UPDATE: I have received few answers after my last update and i am able to solve the problem partially. Using transitionWithView as in the answer below, it is working and cross fading the way i want BUT since i am using a tableivew controller that is loading more entries when it touches the bottom, it refreshes all the cells once before the new block of entries are loaded, how can i prevent this behaviour?
Looks like you are using the SDWebImageManager in a different file that is necessarily not the UITableViewController class. You can use transitionWithView but not with SDWebImageManager directly if its in a different class.
But in your table view controller class where you are using cellForRowAtIndexPath and linking the image with the imageView of UITableViewCell, you can using transitionView as below:
[UIView transitionWithView:cell.(Your Image View)
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
cell.(Your ImageView).image = [(how ever you are calling it)];
} completion:^(BOOL finished) {
// Optionally you can do anything after the completion
}];
Hope this helps!
You can use UIView transitionWithView:duration:options:animations:completion: method to cross dissolve image view from old image to the new one like this:
[UIView transitionWithView:imageView
duration:0.4
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
// Set the new image
// Since its done in the animation block, the change will be animated
imageView.image = newImage;
} completion:^(BOOL finished) {
// Do whatever when the animation is finished
}];
Just use this code in your completed block where you would normally set the image to the imageView
please refer to the interface definition:
- (id<SDWebImageOperation>)downloadWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletedWithFinishedBlock)completedBlock;
there are several value for SDImageOptions and I think this one is what you expected:
/**
* This flag enables progressive download, the image is displayed progressively during download as a browser would do.
* By default, the image is only displayed once completely downloaded.
*/
SDWebImageProgressiveDownload = 1 << 3

Is there any way to stop an image in a UIImageView from lazy loading with SDWebImage on iOS?

I'm using the following code to lazy load an image into my UIImageView:
[self.imv1 setImageWithURL:[NSURL URLWithString:myURL]
placeholderImage:[UIImage imageNamed:#"loading.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType)
{
// stuff here
}];
When a user touches a button, I want the lazy loading of this to STOP completely, so that no image gets loaded and the download of the image stops.
After I stop the lazy loading, I plan to load a different image into the same UIImageView.
Is this possible with SDWebImage?
Found out how to do it. I just needed to call this:
[self.imv1 cancelCurrentImageLoad];

Resources