Loading multiple images in sequence on iPad - iphone

I'm working on an application that talks home to a server and retrieves some data with image URL's embedded in it. I want to display those images on the view, and am getting them like so:
UIImageView *ivAvatar = [[UIImageView alloc] initWithImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.avatarUrl]]]];
[self.view addSubview:ivAvatar];
[ivAvatar release];
However, whenever data is retrieved (for example, on startup of the application), there is a delay between the retrieval of the data and the user being able to interact with the application due to the blocking nature of dataWithContentsofURL.
What is the proper way to do "Asynchronous" downloading of images? I need the UI to be responsive and load all other data that is retrieved, but load the images while allowing the UI to be responsive.
Any suggestions?

NSURL, NSURLRequest, and NSURLConnection.

Related

Best approach for integrating custom graphics in iOS development

What are the best references to read (online resources or books) to read about the approaches and techniques for integrating custom images, graphics, icons for iOS apps? (What are the best strategy to manage custom images for iOS development?)
Uh, ok, not sure if you need super high level OpenGL graphics performance but if you're making ordinary iPhone apps (not games), then maybe these starter knowledge can guide you.
This is from my own limited experience but there are two types of graphics that I distinguish: graphics that are packaged with the app and graphics that are loaded through some network or file on the device.
For graphics that are packaged with the app, these tend to be the buttons and backgrounds for the look and feel of an app.
With these kind of graphics, to display an image to your application, the general idea is you create a UIImageView then add it as a subview of your View Controller's view. You then tell your image view object the image you want to display.
// create the image view object to display the image
UIImageView *myImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,100,100)];
// tell the image view object the image you want to display
[myImageView setImage:[UIImage imageNamed:#"mybutton.png"]];
// add the image view object to your view controller's view
[self.view addSubview:myImageView];
[myImageView release];
As for network images, I usually get the URL of the image I want to display, then use a image caching library such as SDWebImage to load the image like so:
NSURL *url = [[NSURL alloc] initWithString:#"http://www.mysite.com/images/myphoto.png"];
[myImageView imageWithURL:urlOfImage placeholder:[UIImage imageNamed:#"placeholder.png"]];
[url release];
How you get the URL path to your image from the network is a different matter though. If you're loading through a web service, you usually have to fetch it from the JSON or XML output.

Asynchronous images - Meant for displaying images from web only?

I have images in my documents folder which I am displaying on one of my screens. It takes times to load the images and display them on the screen similar to when loading images from web. As far as I know asynchronous imageView works for the later case. I might be wrong.
Is there anyway we can display images from documents folder asynchronously?
Take a look at SDWebImage. It is a UIImageView subclass that lets you display image asynchronously from a URL and with a useful cache. It is designed to work with Internet URLs, but I think it will also go with internal URLs.
Put the loading of images in the background thread as following
-(void)backgroundLoadImageFromPath:(NSString*)path {
UIImage *newImage = [UIImage imageWithContentsOfFile:path];
[myImageView performSelectorOnMainThread:#selector(setImage:) withObject:newImage waitUntilDone:YES];
}
Then call that thread wherever you need to set the image
[self performSelectorInBackground:#selector(backgroundLoadImageFromPath:) withObject:path];
Note, in backgroundLoadImageFromPath you need to wait until the setImage: selector finishes, otherwise the background thread's autorelease pool may deallocate the image before the setImage: method can retain it.

How Do I speed Up Image Loading Using The Assets Library?

I am writing an app that is a clone of the UIImagePicker but uses the Assets library. When the user selects a photo, it takes a little bit too long for the image to load. I notice that when I use the photos app which has identical functionality as to what I'm developing, that the image loading is a bit faster. I've heard another responder on this site mention the following in order to mimic the functionality of the photos app:
"Load the thumbnail image first (best with dispatch_async) - that should be really quick. When this has completed, load the fullscreen image like you did above. This is what apple does in the Photo App to provide a smooth user experience."
Does anyone have any code samples of how this can be accomplished? I'm not quite sure that I understand what he means.
Also here is my code for which I'm using to load an image (I'm passing the image as a parameter to another view controller):
myImage = [UIImage imageWithCGImage:[[myAsset defaultRepresentation] fullScreenImage]];
The class ALAsset has two methods to obtain thumbnails:
- (CGImageRef)thumbnail
- (CGImageRef)aspectRatioThumbnail
I bet they are faster than obtaining the full screen sized version of the asset.
Also, you can wrap them with an async operation. Be sure to update the UI in main thread. Roughly like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* obtain the image here */
dispatch_async(dispatch_get_main_queue(), ^{
/* update screen here */
});
[pool drain];
});
If you need to obtain thumbnails for videos you should use AVAssetImageGenerator. It has a method to obtain them asynchronously.
Look for Apple sample code (AVEditDemo and probably others working with assets library).

UIImage in uitableViewcell slowdowns scrolling table

I am loading image with data in my table view. Images are coming from web. I created method to get image url in model class.Model class has Nsdictionary and objects.
But this images is slowing down scrolling .Here is my code
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",
[(Tweet *)[recentTweets objectAtIndex:indexPath.row]urlString]]]]];
cell.imageView.image = image;
Please tell Where I am going wrong?
Use lazy loading and do your own drawing. Try to understand the techniques on the sample projects I linked. These are the best ways to improve the performance of tables with images.
here is the methodology I use for loading images into a UITableView from a remote location:
in your .h file, declare a mutable dictionary for storing the images:
NSMutableDictionary *images;
initialize the dictionary in -init... or in -viewDidLoad
images = [[NSMutableDictionary alloc]init];
in the .m, tableView:cellForRowAtIndexPath:, see if the image exists in your dictionary for the indexPath
UIImage *img = [images objectForKey: indexPath];
if the image does exist, just set it.
if (img) cell.imageView.image = img;
if the image does NOT exist, set the cell's image to a temporary image...
if (!img) cell.imageView.image = [UIImage imageNamed:#"imageUnavailable.png"];
AND add that image to your dictionary so it doesnt try to refetch the image if you scroll off and back to that image before it loads...
[images setObject:[UIImage imageNamed:#"imageUnvailable.png"] forKey: indexPath];
then, in this same block, use an NSOperationQueue, and a custom NSOperation ( here is a reference - NSOperation and SetImage) to get your image and call back into your UITableViewController with that image.
in your callback, add your image to the dictionary (overwriting the temp image) and call [tableView reloadData]
this will give you a nice non blocking user experience.
The are a couple of ways how to do it. I had the best experience with a Queue for the HttpRequests, which I pause during the scrolling process.
I highly recommend this framework for that:
http://allseeing-i.com/ASIHTTPRequest/
I also implemented an image cache, which only loads the images if there weren't in the cache.
And the last tweak was to actually draw the images instead of using a high level uicomponent like the UIImageView
The number one reason your code is slow right now is because you're making a network call on the main thread. This blocks an UI from being updated and prevents the OS from handling events (such as taps).
As already suggested, I recommend ASIHTTPRequest. Combine asynchronous requests with an NSOperationQueue with a smaller concurrency count (say, 2) for the image requests, caching, and reloading the rows when images come in (on the main thread) (also only reloading the row if its currently visible). You can get a smooth scrolling table view.
I have an example of this on github here: https://github.com/subdigital/iphonedevcon-boston
It's in the Effective Network Programming project and includes a set of projects that progressively improve the experience.
Download the images before you load the tableView, and store them in an NSArray. Then when the cellForRowAtIndexPath method is called, show a loading image until the image is in the array.

Memory Management

I need a clarification from all of you,That is I am implementing an iPad application. In that I tried to download and animate the images. The image count should be more than 100,000.The code I used to download and adding to the view is as follows.
UIImageView* imageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0,100,100)];
NSData *receivedData=nil;
receivedData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://path/prudently/iphone/image_s/e545afbf-4e3e-442e-92f9-a7891fc3ea9f/test.png"]];
imageView.image = [[UIImage alloc] initWithData:receivedData] ;
[subView addSubview:imageView];
[imageView release];
But I am getting exception after I successfully added more than 8000 image to my subview. I am getting exception at getting data from the url. And one more thing I am not releasing the subview because once I downloaded them I need to animate the subview.
Please give me your suggessions
Thank you,
Sekhar Bethalam.
100,000 images would seem a lot for desktop applications, let alone a smart phone like an iPhone. Is there not another approach you can take to solve this problem that wouldn't need such a high resource count?
You can write the URL , images or something to a cached file, and divide some pages to animate the images...
When the user press a page link , application read and animate the images of this page, images of the page which user don't use need not display.
The only way you are going to accomplish this is to dynamically create and destroy the UIImageViews as they are needed on the screen. The iPhone/iPad/iAnything are incapable of doing what you want because of the limited memory available on the device.