I checked the NSBundle but couldn't find the cache where the images are saved by SDWebImage. Is the cache even enabled (see code below)? According to the Docs it does the caching management.
As given in docs:
Just #import the UIImageView+WebCache.h header, and call the
sd_setImageWithURL:placeholderImage: method from the
tableView:cellForRowAtIndexPath: UITableViewDataSource method.
Everything will be handled for you, from async downloads to caching
management.
#import <SDWebImage/UIImageView+WebCache.h>
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided sd_setImageWithURL: method to load the web image
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
In your sandbox's Library folder
Your Application ID/Library/Caches/com.hackemist.SDWebImageCache.default/
Search below line of code in your project. _diskCachePath is the cache of SDWebImage.
if (![_fileManager fileExistsAtPath:_diskCachePath]) {
[_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
}
Related
I am trying to download images in the UITableViewCell using multi-thread. However, when I using the simulator to see the results, the images can not be loaded until I scroll the table view.
I have watched many examples and tutorials in StackOverFlow, but it still doesn't work at all. Actually, I download the images from the Flickr server and stored them into a cached dictionary. But I could still load the images for the first time, unless I scroll the table view and the images start to appear.
And here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
NSString *cellIdentifier = [NSString stringWithFormat:#"cell%ld", (long)indexPath.row];
NSDictionary *photo = self.recentPhotos [indexPath.row];
NSString *title = [photo valueForKeyPath:FLICKR_PHOTO_TITLE];
cell.textLabel.text = title;
[cell.textLabel setFont:[UIFont fontWithName:#"OpenSans" size:18]];
if ([self.cashedImages objectForKey:cellIdentifier] != nil) {
cell.imageView.image = [self.cashedImages objectForKey:cellIdentifier];
}
else
{
dispatch_queue_t queue = dispatch_queue_create("fetch photos", 0);
dispatch_async(queue, ^{
NSURL *imageURL = [FlickrFetcher URLforPhoto:photo format:FlickrPhotoFormatSquare];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
dispatch_async(dispatch_get_main_queue(), ^{
if ([tableView indexPathForCell:cell].row == indexPath.row) {
[self.cashedImages setValue:image forKey:cellIdentifier];
cell.imageView.image = [self.cashedImages valueForKey:cellIdentifier];
}
});
});
}
return cell;
}
For this task probably it is better to use a library. Usually I use the SDWebImage which is very easy to use, and handle image cashing also.
https://github.com/rs/SDWebImage
One example could be:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] ;
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
EDIT:
If you want to download all the images first and cache them you shouldn't handle this in a tableviewCell. TableViewCells will start the download, when it is created -> when they become visible.
SDWebImageView cashes the images that has been downloaded before so try to add this code in the viewDidLoad method:
for (NSURL* url in self.recentPhotos) {
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:url options:SDWebImageContinueInBackground progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
//Your code if needed
}];
}
SDWebImage caches the images based on their absolute url path.
Note! GDImageLoader now (2016) has full, awesome, Swift version. It is maintained on an almost daily basis - it's really perhaps the single most critical and basically perfect library in iOS. Until Apple sensibly just include caching, it's basically a must-use library.
GDImageLoader is incredibly simple, solid - it's the best ..
https://github.com/AndreyLunevich/DLImageLoader-iOS/tree/master/DLImageLoader
No manual, no learning curve - one command. Totally fantastic.
-(UICollectionViewCell *)collectionView:(UICollectionView *)cv
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger thisRow = indexPath.row;
MeetingsCell *cell;
cell = [cv dequeueReusableCellWithReuseIdentifier:
#"CellPlayersB2" forIndexPath:indexPath];
cell.layer.shouldRasterize = YES; // TYPICALLY NEEDED ON iPhone6+
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
NSDictionary *mtg = CLOUD.players[thisRow];
NSString *hostText = mtg[#"host"]; etc...
cell.whenDescrip.text = etc ...;
NSString *imUrl = mtg[#"image"];
__weak UIBookView *loadBooky = cell.booky;
[DLImageLoader loadImageFromURL:imUrl
completed:^(NSError *error, NSData *imgData)
{
if (loadBooky == nil) return;
[loadBooky use:[UIImage imageWithData:imgData]];
}];
return cell;
}
Possibly the table doesn't redraw it's content. One fix could be to save the image in self.cashedImaged (you know that a typo, right ;) ) and then instruct the UITableView to reload the single cell using reloadRowsAtIndexPaths:
I think it will be better to add a Category on UIImageView and add a method something link this:
#interface UIImageView (Caching)
- (void)setImageWithFlickrURL:(NSURL *)url;
#end
And put your caching logic there.
And then in your cellForRow:indexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
NSURL *imageURL = [FlickrFetcher URLforPhoto:photo format:FlickrPhotoFormatSquare];
[cell.imageView setImageWithFlickrURL:imageURL];
return cell;
}
Or, you can just use caching mechanism that provides AFNetworking's UIImageView+AFNetworking
- (void)setImageWithURL:(NSURL *)url;
You need to add one line:
cell.imageView.image = [self.cashedImages valueForKey:cellIdentifier];
//add this line to make tableview redraw
[cell setNeedsLayout];
I have an UITableView which downloads its UITableViewCells images from a server.
I observed that the table scrolls very slowly.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"parallaxCell";
JBParallaxCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSURL *imageURL = [NSURL URLWithString:[[news objectAtIndex:indexPath.row]objectForKey:#"Resim"]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad = [[UIImage alloc] initWithData:imageData];
cell.titleLabel.text = [[news objectAtIndex:indexPath.row]objectForKey:#"Adi"];
cell.subtitleLabel.text = [[news objectAtIndex:indexPath.row]objectForKey:#"Resim"];
cell.parallaxImage.image = imageLoad;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
You are loading image file on main thread and this operation is slowing your scroll. Use UIImageView+AFNetworking.h from AFNetworking to speed up your app by async image loading. link https://github.com/AFNetworking/AFNetworking
I use this Library which is just perfect
SDWebImage
You just need to #import <SDWebImage/UIImageView+WebCache.h> to your project, and you can define also the placeholder when image is being downloaded with just this code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
It also cache downloaded images and gives you great performance.
Hope it will help you!
Load the images asynchronously. It will help you :
Loading an image into UIImage asynchronously
Link
At the moment, I'm using the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
PFFile *file = [object valueForKeyPath:#"exercicio.foto"];
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
cell.imageView.image = [[UIImage alloc] initWithData:data];
[cell setNeedsLayout];
}];
return cell;
}
This works, but the images take too long to load, and visual effects are not so good when scrolling. I tried to use PFTableViewCell, but I get the message, unrecognized selector sent to instance in the line cell.imageView.file when I try to get my PFFile from parse. Now, when I change the class in storyboard to PFTableViewCell, app doesn't crash, but no images are loaded as well.
This is the code that gives me crash or in case I change storyboard to PFTableViewCell, it doesn't show the images.
- (PFTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
PFTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.imageView.file = [object valueForKeyPath:#"exercicio.foto"];
return cell;
}
I really need help with this, I've tried a lot of things but nothing seems to work. Thanks.
This works
PFFile *thumbnail = object[#"imageFile"];
cell.imageView.image = [UIImage imageNamed:#"857-rocket.png"];
cell.imageView.file = thumbnail;
[cell.imageView loadInBackground];
If the problem is that your images take too long to load, I would recommend you create thumbnail versions of your images and then use those in the tableview. Then, if you go from tableview to a detail-view, you load the full size image.
You have to call loadInBackground after setting the file value of your PFImageView
- (void)loadInBackground
Parse docs description for the file attribute confirms that :
The remote file on Parse’s server that stores the image. Note that the
download does not start until loadInBackground: is called.
There is also a method with a completion block :
- (void)loadInBackground:(void ( ^ ) ( UIImage *image , NSError *error ))completion
I am trying to load an image form the internet into a cell.
When I'm using a single row then it's not taking much time, but when I have more then 5 rows then it is blocking UI. How can I solve this?
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
In this method: I am using that Code:
NSURL *url = [NSURL URLWithString:upcImageLink];
NSData *data = [NSData dataWithContentsOfURL: url];
UIImage *imageObj = [[UIImage alloc] initWithData:data];
[iconImgVw setImage:imageObj];
If I understand correctly, you are currently, making sync calls to download the tableview cell image. Sync call takes time and your screen/UITableView becomes unresponsive to touch events. The technique to avoid this is called Lazy loading.
Use SDWebImage for lazy loading of tableview images. Usage is simple,
#import <SDWebImage/UIImageView+WebCache.h>
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
Alternatively, you can also implement lazy loading of image on your own refering to the Apple sample code.
Hope that helps!
please try the following code by replacing url:
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^(void)
{
NSData * data = [[[NSData alloc] initWithContentsOfURL:URL] autorelease];
UIImage * image = [[[UIImage alloc] initWithData:data] autorelease];
dispatch_async( dispatch_get_main_queue(), ^(void){
if( image != nil )
{
[iconImgVw setImage:image];
} else {
//error
}
});
});
I am loading the image to the tableView, each time function
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
is executed, different url of image will come..
My problem is its taking so much time to load the image..
My code is..
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
self.tableView1 = tableView;
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView1 dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.nameLabel.text = title;
NSString *imageURL = [NSString stringWithFormat: #"http://www.xyz.com/image1.png];
cell.thumbnailImageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:fullURL]]];
}
return cell;
}
every time the image url will change and it will take time to load each image..
can any one suggest any idea to solve this problem?
how multithreading will work with this code?
where and what should i edit in the code?
You have to download image in background like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView1 dequeueReusableCellWithIdentifier:simpleTableIdentifier];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSString *u=[NSString stringWithContentsOfFile:r.url encoding:NSUTF8StringEncoding error:nil];
NSURL *imageURL=[NSURL URLWithString:u];
NSData *imageData=[NSData dataWithContentsOfURL:imageURL];
dispatch_sync(dispatch_get_main_queue(), ^{
SimpleTableCell *cell = (SimpleTableCell *)[tableView cellForRowAtIndexPath:indexPath];
cell.thumbnailImageView.image=[UIImage imageWithData:imageData];
[cell setNeedsLayout];
});
});
}
return cell;
}
Just use above code in your table view method with required edit this should work for you.
You don't need multi threading. At least you don't need to do that on your own.
Have a look at this tutorial. It was very helpful for me when I started with Apps.
http://www.markj.net/iphone-asynchronous-table-image/
Alternatively subclass UIImageView and do this:
http://codeshape.wordpress.com/2011/05/10/creating-a-lazy-loading-uiimageview-for-ios/
Take a look at the SDWebImage framework:
SDWebImage Framework
Maybe it'll help you.
An alternative to Jeremy's answer which i have used before is the HJCache framework
Can just use the HJManagedImage object, it will download and cache the image asynchronously for you