I use the SDWebImage image downloading/caching library pretty much any time I display an image in a table view.
I would usually implement it like so (in a table view cellForRowAtIndexPath method).
[cell.imageView setImageWithURL:
[NSURL URLWithString:#"http://asite.com/animage.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
And that would load a cached version if it had one.
What about if I wanted to use the simplicity of SDWebImage (with the placeholder / robust downloading code) - but without the cache in just one place.
I know how to disable caching throughout SDWebImage, but I don't know how you would call setImageWithUrl: placeholderImage: making sure that SDWebImage doesn't use any cache?
The reason I want to do this is I'm using it to display webcams in a table view (obviously, you want this updated every time).
I recommend moving away from the Category on UIImageView and creating your own version of SDWebImageManager. You'd get more control if you use the class SDImageCache yourself.
Heres and example right from SDWebImageManager itself:
[[SDImageCache sharedImageCache] storeImage:image
imageData:downloader.imageData
forKey:[downloader.url absoluteString]
toDisk:NO];
toDisk is probably where I changed the BOOL to NO, the default manager uses disk caching. You may also want to clear the memory every so often to support your streaming images:
[[SDImageCache sharedImageCache] clearMemory];
The SDWebImageManager code is easy to follow and I imagine you won't need to reinvent most of it, just a few important portions to suit your needs.
Here you go. Make sure you get the latest version of SDWebImage:
[anImageView setImageWithURL:[NSURL URLWithString:#"http://asite.com/animage.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]
options:SDWebImageCacheMemoryOnly];
From SDWebImageManager.h:
/**
* This flag disables on-disk caching
*/
SDWebImageCacheMemoryOnly = 1 << 2,
Swift 4.2
Xcode: 10.0
SDWebImage: ~>4.0
SDImageCache.shared().config.shouldCacheImagesInMemory = false
You just need to use the shouldCacheImagesInMemory property from SDImageCache and set it to NO.
This feature available in 3.7.4+.
You can use SDWebImageDownloader. It doesn't cache data.
You should use SDWebImageManager.shared.loadImage with fromLoaderOnly option
Related
I have this app with one whole set of images, but I would like to add for example personalized set of graphics. Is there an easy way to organize and develop source code and not to get lost while switching between these sets of images?
One way I see it is to have on my hard drive two folders with graphics and before releasing replace in project current images with personalized set... is there a better way?
I'm using Xcode 4.2 and iOS 5.0 for this app.
Probably the easiest and most reliable in terms of maintainance is to write your own image access function or marco, that is controlled in one place globally. Then use this in all cases where you want to have the flexibility for differnt images for example like this. I just got used to this way of assigning an image with stretchableImageWithLeftCapWidth because it adjusts the size nicely.
Of course you may use any other way to assign your images, like directly without use of stretchableImageWithLeftCapWidth
Anyway, this is my suggestion:
NSString *s = [NSString stringWithFormat:#"%s%i",#"imageName",CONST_VERSION];
UIImage *theImage = [UIImage imageNamed:s];
myImageView.image = [theImage stretchableImageWithLeftCapWidth:12 topCapHeight:0];
and you can do
#define CONST_VERSION 1 // or 2
Then name your images like:
myImage1.png
and
myImage2.png
I am building a photo album app and find a few image caching libraries, namely:
JMImageCache
HJCache
SDWebImage
What one you'd recommend (or other libs not on the list)? I am looking for:
Efficiency
Minimum effort in terms of garbage collection
Support for Blocks preferred
Thanks
Personally, I think SDWebImage is the best because it is an absolute no-effort solution, and provides the simplest mechanism for cache handling as it is simply an extension of the UIImageView class.
Image async downloading and caching is not a simple task. It needs to be done well otherwise it will defeat its purpose. Therefore I strongly suggest that eventually you build your own. Having said that, I needed a quick and simple solution in order to move forward with the development of my application.
I found these solutions:
HJCache
SDWebImage
Apple's LazyTableImages
An adaption from Apple's LazyTableImages,MHLazyTableImages
I tried HJCache, but it didn't offer great scrolling performance when handling large images (1.5M+). For small images it worked great though. Tried both LazyTableImages as well but the integration wasn't simple.
Ultimately, I chose SDWebImage. The integration couldn't be simpler. Once you have linked the library to your project all you need to do is:
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
in your tableView:cellForRowAtIndexPath:.
Additionally:
Works with custom cells as well
Doesn't block the UI
Offers great scrolling performance
Image downloading and caching is seamless.
There are multiple frameworks that solve this problem. Just to name a few:
Swift:
Nuke (mine)
Kingfisher
AlamofireImage
HanekeSwift
Objective-C:
AFNetworking
PINRemoteImage
YYWebImage
SDWebImage
Try also APSmartStorage. It automatically caches UIImage/NSData on disk or in memory.
It has cute Blocks–style API;
// setup data parsing block
APSmartStorage.sharedInstance.parsingBlock = ^(NSData *data, NSURL *url)
{
return [UIImage imageWithData:data scale:UIScreen.mainScreen.scale];
};
...
// show some progress/activity
...
// load object with URL
[APSmartStorage.sharedInstance loadObjectWithURL:imageURL callback:(id object, NSError *error)
{
// hide progress/activity
if (error)
{
// show error
}
else
{
// do something with object
}
}];
It's quite smart and still simple:
I tried using SDWebImage.
Agreed that it is very easy to integrate.
However the big issue with this library is that it does not honour "max-age" cache control.
The library is still under development but they are not picking this limitation.
I strongly recommend you to try Kingfisher and SDWebImage. Both works perfectly for downloading and caching images from the web.
Moa
Moa is an image download library written in Swift. It allows to download and show an image in an image view by setting its moa.url property.
Installation
Use CocoaPods to add Moa to your project. Just add the following line to your Podfile.
pod 'moa', '~> 8.0'
Does anyone know of a good tutorial that shows how to lazy load images in a UITableView? I've searched online but the only one I found that looked like it did what I wanted was hard to follow because only parts of the code were shown and I'm new at this so I didn't understand how to hook everything up.
I suggest you check out the SDWebImage project on github, I use it for my table views when I need to load a remote image into the cells.
https://github.com/rs/SDWebImage
As Daniel suggested SDWebImage https://github.com/rs/SDWebImage, I don't know of any tutorial, but in amongst the KTPhotoBrowser samples there is one that uses SDWebImage that can show you how to do it https://github.com/kirbyt/KTPhotoBrowser/tree/master/src/Sample/Classes/SDWebImageSample
If I remember correctly you need to import and use the SDWebImage UIImageView category and then pass the url to the cell and call
setImageWithURL:[NSURL URLWithString:#"yoururl"] placeholderImage:[UIImage imageNamed:#"placeholder.png"]
when setting the cell image.
I haven't actually followed it, but this one has plenty of positive commentary: http://www.markj.net/iphone-asynchronous-table-image/
I am loading images using the JSON.
But it makes app slow as it use to wait until all images are downloaded in app.
To avoid this situation I want to put some default image. And when app downloads image it should replace that default image.
I am not using table view. I am displaying this images in coverflow.
How do I get this ?
This sample demonstrates a multi-stage approach to loading and displaying a UITableView. It begins by loading the relevant text from an RSS feed so the table can load as quickly as possible, and then downloads the images for each row asynchronously so the UI is more responsive.
http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
check out Web Image https://github.com/rs/SDWebImage/
it has:
setImageWithURL:placeholderImage:
method which you can use like:
[imageview setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
Also check out TTImageView from the Three20 library.
Set the property
photoView.defaultImage = defaultImage;
defaultImage(on right ) is the UIImage
I want to load some images into my application from the file system. There's 2 easy ways to do this:
[UIImage imageNamed:fullFileName]
or:
NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
NSData *imageData = [NSData dataWithContentsOfFile:fileLocation];
[UIImage imageWithData:imageData];
I prefer the first one because it's a lot less code, but I have seen some people saying that the image is cached and that this method uses more memory? Since I don't trust people on most other forums, I thought I'd ask the question here, is there any practical difference, and if so which one is 'better'?
I have tried profiling my app using the Object Allocation instrument, and I can't see any practical difference, though I have only tried in the simulator, and not on an iPhone itself.
It depends on what you're doing with the image. The imageNamed: method does cache the image, but in many cases that's going to help with memory use. For example, if you load an image 10 times to display along with some text in a table view, UIImage will only keep a single representation of that image in memory instead of allocating 10 separate objects. On the other hand, if you have a very large image and you're not re-using it, you might want to load the image from a data object to make sure it's removed from memory when you're done.
If you don't have any huge images, I wouldn't worry about it. Unless you see a problem (and kudos for checking Object Allocation instead of preemptively optimizing), I would choose less lines of code over negligible memory improvements.
In my experience [UIImage imageNamed:] has dramatically better performance, especially when used in UITableViews.
It's not just the memory but also decoding the image. Having it cached is much faster.
As the API reference of UIImage says :
+(UIImage *)imageNamed:(NSString *)name
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
+(UIImage *)imageWithContentsOfFile:(NSString *)path
This method does not cache the image object.
so,we can see that if you have a lot of same UI elements(such as UITableViewCell) that may use same image(often as an icons),and due to performance , of course we want to reuse the same image , so that we will save some memory for other use . Generrally the reused image is often used in the ui element that our user may operate on it lots of times . So it values for us to reuse it .So you can choose to use imageNamed method .
And on the other hand , in an application , there will be some UI element that will be there during the app's life cycle,such as a Button , a logo view , so these images used by these ui elements may also be there during the app's life cycle ,you wouldn't consider whether these image should be cache or not .So you can choose to use imageNamed method .
On the contrary,in an application , there are often some UI Elements that created dynamically. For example , our application support dynamic background , so that user can choose the background they like .And the background may be an image .So we may have a interface that list lots of different background (often show by use UIImageView) for user to choose ,we can name the list view MyBackgroundListView.So once the user chooses an background image , the MyBackgroundListView should be destroyed , because it has finishs its function .The next time the user want to change his/her background , we can create MyBackgroundListView again .So the images used by MyBackgroundListView shouldn't be cached , or our application's memory will run out .So this time you should use
imageWithContentsOfFile method.
As the Apple's doc Supporting High-Resolution Screens In Views says
On devices with high-resolution screens, the imageNamed:, imageWithContentsOfFile:, and initWithContentsOfFile: methods automatically looks for a version of the requested image with the #2x modifier in its name. If it finds one, it loads that image instead. If you do not provide a high-resolution version of a given image, the image object still loads a standard-resolution image (if one exists) and scales it during drawing.
so you would worry about the image's search path for retina screen problem . IOS will help you deal with it.
Sorry for my poor English . May it be helpful.
If you don't want your image do be cached you can also use initWithContentsOfFile directly :
NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];
UIImage* yourImage = [[[UIImage alloc] initWithContentsOfFile:imagePath] autorelease];
I've also been told that [UIImage imageNamed:] does a little bit too much caching, and images are not often released. I was told to be careful of using it.
imageWithData is useful when you store your image binary in a database or progressively downloading large image from the web.
I would not use imagenamed if your app has loads of big images which are not the same. I experienced app crashing due to using too much of it.
I don't believe that the image gets cached at all, and I don't know why you are all saying that. UIImage is a subclass of NSObject which uses reference counters to keep track of the things that it is related to. So when you load an image it does that same thing. If you load the same image multiple times it will(or should) have only one copy of the image in memory and just increment the reference counter every time you have to use something with that image. By Reference Counters I mean that when the count gets to 0 it deletes itself. so "alloc", "retain" are each +1 to the count and "release" is -1. Not only is it a better way to manage memory but this style of programming also helps clean up memory leaks.