I have some performance problem with NSData dataWithContentsOfURL...
NSURL *url = [NSURL URLWithString:Imagepath];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img=[UIImage imageWithData:data];
[ArrayImages addObject:img];
This code is placed in a method that manage a JSON response got from an NSUrl connection(after calling my web service). All the code in this method is already in a background thread, moving this piece of code out the background thread do not solve the issue.. All the retrieved image are placed in a view in main thread. What i can do to make dataWithContentsOfURL faster or there is a alternative to dataWithContentsOfURL?
Thanks In Advance
+[NSData dataWithContentsOfURL:] is not "slow". If loading one image takes a long time, the problem lies elsewhere.
Evaluate your problem. For starters:
Which resource is the bottleneck? Probably the Network.
How do you load images? All at once? That would be bad -- display them as they become ready.
What are the sizes of the images? I saw one SO question where the poster wanted to load 50 MB images. That's way too large. As well, if all you need is a thumbnail, then be sure you request the thumbnail from the server and load that and not the full-sized image.
Are you loading things you don't even need to display? Wait until you need to display them.
How many threads are you using for Network tasks? For CPU? For I/O?
Are your source images properly "crushed"?
Write your program so it flows with your program's presentation model. Example: I had a bazillion images to display in tables, but I made sure to minimize resource usage and made sure load and request cancellation was well supported for the app. This was all coming through the network, and it was plenty fast (it was network-bound).
and if you are loading many images from device storage, you should consider using -[UIImage initWithContentsOfFile:] instead because your image data would not be cached, but can be purged.
U need to use Lazy loading for images display as content will displayed as image gets downloaded.
Use SDWebImage which uses lazy loading of images.
Related
What is the best way of loading images from the application main bundle. I am using
[UIImage imageNamed: "image.png"];
But I have heard that this is not good in terms of memory usage and performance. Can anyone please give his/her feedback on it? My application reads lots of images from main bundle at launch time. I want to make this process as efficient as possible.
Best Regards
If there were one true "Best Way", the means to load images multiple ways would not exist (unless for historical reasons). Therefore, a little understanding will serve you better than distilling an answer down to a "Best Way".
+[UIImage imageNamed:] caches the image for reuse, and it is a sensible default for most purposes. Caching is excellent if used correctly. The cache is good because it can minimize your disk reads and memory usage by sharing and reusing loaded images, rather than reading and allocating a copy for each image you must display. Consider an icon image which you use on multiple screens - would you like that image data to be read and reallocated each time? This may result in redundant reads and allocations of identical image data. If not, use the caching methods.
If you load the image only once and lazily, then you may want consider non-caching approaches.
Image data can consume a lot of memory.
Reading an image can take a long time -- not just disk i/o, but also converting it into a usable UIImage representation (e.g. decompressing the image).
there are also times where you should resize/scale an image. then you'd want a scaled copy.
In short, there are many considerations, but if you have properly scaled assets which you reuse, caching is typically the right choice.
If your assets are not sized properly, then the issue is more fundamental -- you should resize the bundled assets to be appropriate for the purpose if you're experiencing performance problems. Properly sized images also make drawing significantly simpler while retaining the best image quality.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"myimage" ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
If you want to try loading the images without caching, you can use:
[[UIImage alloc] initWithContentsOfFile:#"image.png"];
This could be slightly faster loading the image for the first time, since it doesn't have to cache it first. If you only need to use these images once, it probably makes sense to try it this way. The other benefit of doing it this way is that you won't have an image cache using up memory for longer than necessary.
For finding a single resource file using NSBundle
NSBundle* myBundle = [NSBundle mainBundle];
NSString* myImage = [myBundle pathForResource:#"Seagull" ofType:#"jpg"];
and for finding multiple resources:
NSBundle* myBundle = [NSBundle mainBundle];
NSArray* myImages = [myBundle pathsForResourcesOfType:#"jpg"
inDirectory:nil];
When I try to fetch the images in UITableView using NSURLUIImage image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://mysite.com/mobile/abc.jpg]]];
my application get freezes until the images loaded. Also when I scroll the table it get images from the server again and scroll get stuck for some time.
I know this is happening because of downloading images synchronously from server.
Is there any solution so that I can download the image asynchronously from server and store it locally or in cache so that when table scrolls it did not get images again from server.
Thanks
Check out EGOImageLoading by enormego. Works just like UIImage (and caches images) but lets you load from HTTP asynchronously.
You can create your own class which leverages NSURLConnection and it's various Asynchronous methods to load your images in the background and then have a callback to display it in the cell.
However, there are some excellent libraries which do exactly what you've described. HJCache is one i've used and recommend for this sole purpose
I'm new to iphone dev, i'm just trying to get something done.
I do my first XML parser App. When my app launches i set a tableView with a custom cell. There is in the custom cell two labels and one image.
When the table view is launched i call my custom cell method which take the string od the image's adress and then make an url with it, a nsdata from the content of an url than i create my image with the content of this data.
But my table view is really really slow even on simulator.
what is the best way to display images on iphone via the internet ? ?
i know they have to be in a png format but even with png it is too slow
thanks for all
i use :
> NSURL *imgUrl = [NSURL URLWithString:_text];
> NSData *imgData = [NSData dataWithContentsOfURL:imgUrl];
> limage.image = [UIImage imageWithData:imgData];
Is your image saved at its final resolution? Say you want to display a 25x25 pixel image in the table, is the file saved as a 25x25 image or is it saved as some higher resolution? This will cause some slowness. However you should be loading the image in a background thread so that when scrolling the scrolling isn't holding up waiting for the image to load. Remember that doing network transfer to get the image is most likely the longest part of the process. You should also cache the image in some way instead of just assigning the image to the limage.image property. This way it won't redownload the image each time it redraws the cell.
Edit
Also you don't have to use PNG images for the pictures in the table cells. You can use regular JPG or GIF images if you want. The image format used should be what ever format is appropriate for the type of image content you will have. You only have to use PNGs for the icons, and splash screens, although it is preferred to use PNG in all embedded resources.
[NSData dataWithContentsOfURL:imgUrl];
Will certainly slow your app down since it will wait for your image to be done loading, called a synchronous call. What you really want is asynchronous calls for fetching the content of the image.
Have a look at http://joehewitt.com/post/the-three20-project/ where you'll find an nice subclass of UIImage that supports handling loading of images by url.
I have UIScrollView with lots of UIImageView inside. In the loadView method I assign some temporary image for each of subview UIImageView images and starts several threads to async download images from internet. Each thread downloads and assign images as follows:
NSData *data = [NSData dataWithContentsOfURL:URL];
UIImage *img = [UIImage imageWithData:data];
img_view.image = img;
Here is the problem - I expects picture will changed after each image downloaded by I can see only temporary images until all images will downloads. UIScrollView still interact while images downloads - I can scroll temporary images inside it and see scrollers and nothing blocks run loop, but downloaded images doesn't updates..
What I tried to do:
Call sleep() in the download thread -- not helps.
Call setNeedsDisplay for each ImageView inside ScrollView and for ScrollView -- not helps.
What's wrong ? Thanks.
Update. I tried some experiments with number of threads and number of images to download. Now I'm sure -- images redraws only when thread finished. For example - if I load 100 images with one thread -- picture updates one time after all images downloads. If I increase number of threads to 10 -- picture updates 10 times -- 10 images appears per update.
One more update. I fixed problem by staring new thread from the downloading threads each time one image downloaded and exit current thread (instead of download several images in one thread in the cycle and exit thread only when all downloaded). Obviously it's not a good solution and there must be right approach.
I would discourage use of threads for this usage, and use an Asynchronous API for data retrieval on the network.
NSData *data = [NSData dataWithContentsOfURL:URL];
This function call sends some data out a socket then sits there and locks the thread until it receives a response. If you don't make any synchronous calls you don't have to worry as much about locking the UI Thread and your problem becomes much simpler.
I would use the ASIHTTP Library or NSURLConnection to access your data, and do all of your updating on one thread. There is a slightly learning curve with the API's but it's substantially smaller than managing threads correctly. I would strongly recommend the ASIHTTP Library, it just rocks. You can set the request delegate to a progress widget and throttle your connection for edge usage.
Hi Newbee (no phun intended)
The situation you describe sounds like a candidate for NSOperation and NSOperationQueue
You can simply "load" everything off to these methods and have them figure out how best
to retrieve the picture. If you keep building new threads, then at some point you loose the advantages of threading, i.e. the overhead grows for each thread and there is only so much CPU time to go around.
Start out by sorting the list of URL's for the pictures so that the ones furthest away from the user (in a scrollView sense) get's loaded last, then start adding the load operation off to an NSOperationQueue and then start the Operation. These classes will then balance things out and save you a ton of coding the logic to deal with scenarios that could erupt.
I found this helpful some weeks ago:
NSOperation tutorial
Marcus Zarra lays out a nice simple example to get you started.
EDIT: Whoops... and to answer your question:) if this does not result in your pictures updating, then you might need to send a specific "update" message when the operation is done.
If this is a large part of your app I would recommend you build a PictureObject and move the functionality inside that. So when adding a PictureObject you instantiate it with a URL and it displays a dummy picture as it's view. The you hand this PictureObject over to your NSOperation who retrieves it's URL loads the picture and sets it on the PictureObject.
This way it is async all the way and you don't have to deal with loops or testing if picture is downloaded etc. etc.
Hope it makes sense.
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.