UIImage in uitableViewcell slowdowns scrolling table - iphone

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.

Related

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.

Load MKMapView in background and create UIImage from it (iPhone & iPad)

I have a situation whereby I need a way of loading an MKMapView with several overlays. This map view shouldn't be shown onscreen, the only reason I require it to load is in order to create an image from the map for use elsewhere.
I have had a look around online but I haven't had any luck with finding a solution to the problem. Please can someone help me out?
Here is what I've tried so far (with no success)
// Load the map view
Logs_Map_ViewController *mapViewController = [[Map_ViewController alloc] initWithNibName:#"Map_ViewController" bundle:nil];
mapViewController.GPSCoordinatesToPlot = [someDictionary objectForKey:kGPSCoords];
// Take a picture of the map
UIImage *mapImage = [mapViewController convertMapToImage];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(mapImage)];
NSString *base64String = [imageData base64EncodedString];
NOTE: It's really important that the app waits for the map to fully load (so that the image is created properly).
This may or may not be helpful but this is what I do in my situation.
I have a tableview for an venue/business with 7 table cells. One of the table cells contains a map with pindrop. When the user views an establishment for the very first time, i run a quick conditional to see if the mapview has been cached (or rather, saved as image). if the image does not exist, i load a fresh mapview into the cell and add a single pindrop annotation. After both the mapview has loaded and the annotation has dropped, i save the view layer to image, then remove the mapview (and release it since we needed to keep the delegate alive) from the cell and replace with the fresh new image. I suggest spawing a background thread to save the image/insert into cell. This way the table view doesn't choke up.
And then finally, the next time the user returns to that same venue/business, the mapview image exists and i load the image.
I know it's important for the map to fully load, otherwise your image saves with gray where the map did not load. if you're dropping a pin drop, you need to make sure your image saving method fires after both the map finished loading (mapViewDidFinishLoadingMap:) and your annotation has dropped (mapView:didAddAnnotationViews:). Only after both have finished should you fire method to save image. i suggest using a delayed selector. I delay it by 1 second.
This same concept can surely be applied to other situations. Bottom line is, as strings42 states, you're going to have to add a visible mapview to your view in order to capture an image.
You should be able to implement mapViewDidFinishLoadingMap in the MKMapViewDelegate protocol and store your image there, I would think. That should solve the problem of needing to wait until the map is loaded to store the image.
If you're seeing other issues as well, please provide more detail on those, as your question is not clear on the specific issue(s) that you're asking about.
The method below will always be called as the delegate of mapView,
mapViewDidFinishRenderingMap:fullyRendered:
so, you can get map image from mapView here
- (UIImage *)renderToImage:(MKMapView *)mapView
{
UIGraphicsBeginImageContext(mapView.bounds.size);
[mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}

UIImage UITableViewCell

How can I pass an image that is in my UITableViewCell to my TableDetailsView.
I tried setting the data on Post, which is my type of data that fills the UITableView cells.
[[cell avatar] setImage:[UIImage imageNamed:#"butterfly.jpeg"]];
[post setImage: [UIImage imageNamed:#"butterfly.jpeg"]]; <-- app crashes here.
All it seems that Question still is not complete....
But looking at two lines of code & you want to pass an image then you could do this thing in lots of ways.
so for testing purpose I will suggest ,just use a Global String i.e in Delegate.
like.Otherwise can you can use this link for Global Variable
Pass a variable between lots of UIVIewControllers
DelegateClassObj.yourGlobalString = [NSString stringwithFormat:#"%#",#"butterfly.jpeg"];
from the class where you want to pass.
&
now if you want to use it:
Suppose post in your imageView then
[post setImage: [UIImage imageNamed:DelegateClassObj.yourGlobalString]];
Hope this will work....the easir way :)
If Your motive is to Display same Image on detail view, then you can pass the name (or Id) of that image on cell tap. and load that image in your detail view through that.

AssetsLibrary and ImageView -setImage Slowness

So this one is pretty odd ad I'm not sure if the trouble is with the AssetsLibrary API, but I can't figure out what else might be happening.
I am loading an array with ALAssets using the -enumerateAssetsUsingBlock method on ALAssetsGroup. When it completes, I am loading a custom image scroller. As the scroller finishes scrolling, I use NSInvocationOperations to load the images for the currently visible views (pages) from the photo library on disk. Once the image is loaded and is cached, it notifies the delegate which then grabs the image from the cache and displays it in an image view in the scroller.
Everything works fine, but the time it takes from when -setImage: actually gets called to the time it actually shows up visibly on the screen is unbearable--sometimes 10 seconds or more to actually show up.
I have tried it both with and without image resizing which adds almost nothing to the processing time when I do the resizing. As I said, the slowdown is somewhere after I call -setImage on the image view. Is anyone aware of some sort of aspect of the AssetLibrary API that might cause this?
Here's some relevant code:
- (void)setImagesForVisiblePages;
{
for (MomentImageView *page in visiblePages)
{
int index = [page index];
ALAsset *asset = [photos objectAtIndex:index];
UIImage *image = [assetImagesDictionary objectForKey:[self idForAsset:asset]];
// If the image has already been cached, load it into the
// image view. Otherwise, request the image be loaded from disk.
if (image)
{
[[page imageView] setImage:image];
}
else {
[self requestLoadImageForAsset:asset];
[[page imageView] setImage:nil];
}
}
}
This will probably mess up any web searches looking to solve problems with the AssetsLibrary, so for that I apologize. It turns out that the problem wasn't the AssetsLibrary at all, but rather my use of multi-threading. Once the image finished loading, I was posting a notification using the default NSNotificationCenter. It was posting it on the background thread which was then updating (or trying to update, at least) the UIImageView with -setImage. Once I changed it to use -performSelectorOnMainThread and had that selector set the image instead, all was well.
Seems no matter how familiar I get with multi-threading, I still forget the little gotchas from time to time.

UIImages on UITableView?

what is the best method to display about 300 png images into a UITableView..
i dont wanna display them at the same time... i have 3 tableViewControllers that will each display about 100 imgaes.. (its for a catalog so the images are important to display)
i used [uiimage imageNamed:] but that method caches the images and they dont get released so the memory usage is big.... is there any way to release the cache when the nav controller pushes a different view controller?
i also tried [uiimage alloc] initWithContentsOfFile] but the images wont display....
any help?
[UIImage imageNamed:#"foo.png"];
is equivalent to
[[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"foo" ofType:#"png"]] autorelease];
except it does not cache the image.
If you write your own caching function, you can purge it at any time. When you need an image, check an NSMutableDictionary by name. If it does not exist, load the image normally and add it to the dictionary with the name as a key. To flush the cache, remove all objects from the dictionary.