xcode Caching images for images in UIScrollview - iphone

I have a list of images retrieve from .xml file and these images are images link from the server e.g. " www.seeimage.com/rice.png"
I am parsing the images everytime I went to that page
-(void)viewdidload{
for (int i = 0; i<[appDelegate.foodItems count];i++) {
NSURL *ZensaiimageSmallURL = [NSURL URLWithString:ZensaiPLUitems.ZensaiimageSmallURL];
NSString *string = [[NSString alloc] initWithFormat:#"%#", ZensaiimageSmallURL];
NSData *simageData = [NSData dataWithContentsOfURL:ZensaiimageSmallURL];
UIImage *itemSmallimage = [UIImage imageWithData:simageData];
[zenbutton2 setImage:itemSmallimage forState:UIControlStateNormal];
[scrollView addSubview:zenbutton2];
}
}
i have been trying out on this tutorial : http://www.iphonedevsdk.com/forum/iphone-sdk-tutorials/13315-image-caching-tutorial.html
but i have no idea on how to implement this in my work.
any idea on how to cache them on the first run and whenever i return to that view ?
i don't want to rerun this method to retrive the images from the website everytime i come to this view.
it takes quite some time to init the images from the website to my UIButton before populating them to the scrollview.

if you do not want to retrieve the images from the website every time then you can download it once and store them e.g. into NSMutableDictionary . And access it whenever you want.
OR
Parse those images in separate thread so that your table view or scroll view will not get paused.

Related

What condition is set in uitableview lazy loading to load images

I fetched images from json and put all image url's in array, rather than calling json again. Now i don't know how to set the condition that it load images as table scrolled. Here is the method i called for this.
+ (NSMutableArray *) createImg: (NSArray*)sampleData
{
NSMutableArray *arrImg = [[NSMutableArray alloc]init];
for(int i=1; i<=[sampleData count]; i++)
{
NSString *strOfUrl = [sampleData objectAtIndex:i];
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:strOfUrl]]];
if(img == NULL)
{
NSLog(#"null no image");
}
else{
[arrImg addObject:img];
}
}
return arrImg;
}
Please guide for the above and feel free to ask anything if not clear in this.
Thanks in advance.
I know this might not be exactly what you are looking for. However, I'd suggest you to use this AsyncImageView. It'll do all the logic you need for lazy loading. Also, it'll cache the images. To call this API:
ASyncImage *img_EventImag = alloc with frame;
NSURL *url = yourPhotoPath;
[img_EventImage loadImageFromURL:photoPath];
[self.view addSubView:img_EventImage]; // In your case you'll add in your TableViewCell.
It's same as using UIImageView. Easy and it does most of the things for you. AsyncImageView includes both a simple category on UIImageView for loading and displaying images asynchronously on iOS so that they do not lock up the UI, and a UIImageView subclass for more advanced features. AsyncImageView works with URLs so it can be used with either local or remote files.
Loaded/downloaded images are cached in memory and are automatically cleaned up in the event of a memory warning. The AsyncImageView operates independently of the UIImage cache, but by default any images located in the root of the application bundle will be stored in the UIImage cache instead, avoiding any duplication of cached images.
The library can also be used to load and cache images independently of a UIImageView as it provides direct access to the underlying loading and caching classes.
use this. It is perfect way to show images while scrolling:
https://github.com/enormego/EGOImageLoading

Store images from web for UITableView

I have a UITableView with custom cells showng text and an image.(image on right side).
At first, it all worked fine, but then I noticed that when scrolling, the whole tableview was lagging. This was because the app probably downloaded the cells image as the cell was entering the screen when re-using them. I added an NSCache to store the downloaded images, and told the cellForRowAtIndexPath to load the imageName if it existed, otherwise, download from the internet again. However, the cache is so short-term storage, that if I exit my app with home-button, and re-enter, then only some of the images remains, and have to download the images again.
I am trying to find out the best possible way to store images more long-term than with cache. I have read some about NSDirectory, and storing in app library, but haven't figured it out yet..
The most logic solution, I believe, would be to do something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
/*stuff*/
NSString *imageName = [dictionary objectForKey:#"Image"];
UIImage *image = [--Cache-directory-- objectForKey:imageName]; //Try to get it from cache
if(image) //If image was received from cache:
{
cell.imageView.Image = image;
}
else //If not in cache:
{
image = [--local-directory-- objectForKey:imageName]; //Check some local directory
if(image) //If image received from directory:
{
cell.imageView.Image = image;
// + Also save it to the cache?
}
else //If image was in neither cache or local directory, get it from the website with given URL
{
image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]];
//Then save to cache and to file?
}
}
}
The images are rarily changed or switched out, but not so rarily that I am willing to implement them in the app beforehand so that I must release an update every time an image is added.
This is what seems logical to me. Am I on the right tracks at all? And how do I "call" the local directory? Like, if I add images to a NSDirectory-object or something, wouldn't this be reset every time? How do I access the local folder?
You are attacking the problem from the wrong direction...
The problem is that the tableView is lagging.
The reason is because you download your images in the main thread.
Even if you will read your images from the disc u still won't get the best scrolling performance.
So must not block your main thread. To do this u can download the picture asynchronously, or use GCD to download in another thread.
like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
/*stuff*/
// this will block your main thread, bad idea..
//image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]];
// instead call it in a separate thread
dispatch_queue_t imgDownloaderQueue = dispatch_queue_create("imageDownloader", NULL);
dispatch_async(imgDownloaderQueue, ^{
// download the image in separate thread
UIImage *image = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]] autorelease];
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_sync(main_queue, ^{
// this is called in the main thread after the download has finished, here u update the cell's imageView with the new image
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.imageView.image = image;
});
});
dispatch_release(imgDownloaderQueue);
}
Theres no need to save all those images.
If you are getting your image from a url then just use AsyncImageLoader
Use that link and get the h and m files of ASyncImageView and save them in your project.
Import the h file where ever you are doing this
#import 'AsyncImageView.h'
Then use the following code
[[AsyncImageLoader sharedLoader] cancelLoadingURL:image.imageURL];
image.imageURL=[NSURL URLWithString:#"imageURL"];
I was working on UITableView recently and i had a similar problem. One work around I used was since the image was small (I assume yours is as well) and had unique name, i stored them in the app's local documents folder and used core data to hold reference to the image location. I load the image from that location. Should the image change, i change those images. This may not be the most elegant method though. just a suggestion.
As for accessing the local app directory, i use this
// INSTANCE METHOD - get the path and file name for the saved plist
- (NSString *)getFileLocation:(NSString *)location {
// Get all available file system paths for the user
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// Get the "Documents" directory path - it's the one and only on iPhone OS
NSString *documentsPath = [paths objectAtIndex:0];
// Specify the file name, appending it to documentsPath above
NSString *savedFileName = [documentsPath stringByAppendingPathComponent:location];
NSLog(#"File Location %#", location);
// We're done
return savedFileName;
}
Seems like the best solution might be using Core Data. But different from what #Anachid suggested you could just load them from the internet like you were doing before and put them in to the core data directory. I suggest the internet instead of putting them in your solution because you would have to update to get new pictures out. Then from there you can use them as needed.

Populating Data from NSMutableArray in iPhone

I have three arrays and I have copied all these arrays into a single array. All these three arrays are arrays of dictionaries.All arrays has a field called picture, but that pictures is coming from different sources- URL in one array, data in other and files in the third one.
Say, Array1 has dictionaries with a key - picture and its loaded from NSURL.
Similarly, Array2 and Array3 has dictionaries with same key name - picture and loaded from ContentofFiles and NSData.
Now, I want to populate tableview, of course,m having Custom UITableViewCell, it has image view as its content view. To load that image, what should I do.
I was doing this thing..
NSURL *url = [NSURL URLWithString:[[contactList objectAtIndex:indexPath.row] objectForKey:#"picture"]];
cell.contactImageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
But, this will crash if cell.contactImageView.image don’t receive image from NSURL.So, what should I do? Any help, will be appreciated
But,
all you is to check if the received image is null and if it is, then set a template photo image called no photo like a photo on facebook when no profile picture is selected
UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if (img)
cell.contactImageView.image = img;
else
cell.contactImageView.image = [UIImage imageNamed:#"no_photo.png"];
If these images are retrieved from the net, i would suggest not using [NSData dataWithContentsOfURL:].
You should be using a non blocking method, that loads images asynchronously. Using this method on numerous rows in a table will cause performance issues.
Here's my recommendation , use the SDWebImage Library . Easy to use, and even easier to install.
Once you add the library to your project, simply #import the UIImageView+WebCache.h class usage example is below.
[cell.contactImageView.image setImageWithURL:[NSURL URLWithString:[[contactList objectAtIndex:indexPath.row] objectForKey:#"picture"]]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
You can add one more key in dictionary which will specify from where to take photo and accordingly you can provide image to cell.contactImageView, if you want to provide image from different sources.
Thanks a lot buddies for your Quick reply,especially #skram, due to your suggestion,my tableview performance has increased much. the Question, that I have asked,the better answer that I have thought of is using iskindofClass. If image is coming from any class, on a condition ,we can check from where that image was coming and populate our image accordingly.
if ([[[contactList objectAtIndex:indexPath.row] objectForKey:#"picture"] isKindOfClass:[UIImage class]])
{
cell.contactImageView.image = [[contactList objectAtIndex:indexPath.row] objectForKey:#"picture"];
}
else if ([[[contactList objectAtIndex:indexPath.row] objectForKey:#"picture"] isKindOfClass:[NSString class]])
{
cell.contactImageView.image = [[contactList objectAtIndex:indexPath.row] objectForKey:#"picture"];
}
else if([[[contactList objectAtIndex:indexPath.row] objectForKey:#"picture"] isKindOfClass:[NSURL class]])
{
[cell.contactImageView setImageWithURL:[NSURL URLWithString:[[contactList objectAtIndex:indexPath.row] objectForKey:#"picture"]]placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
}
Now, I’m able to populate the tableview properly.Once again thanx to scram.

How do I read in & display a local image on UIImageView via SQLite

How may I modify, read in an image path from SQLite DB, & display it via an UIImageView? In other words, this application will work in offline mode & i have the images at hand. How will i go about this then, tgt with sqlite? (retrieve images by storing their image path name # sqlite)
Sample code I have for now:
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate = (SQLAppDelegate *)[[UIApplication sharedApplication] delegate];
//start with index 0
currentStepIndex = 0;
Resolution *resolutionObj = [appDelegate.resolutionArray objectAtIndex:currentStepIndex];
[resolutionDescription setText:resolutionObj.stepDescription];
//checking for null string
//replicate of ifelse #goToNextStep & #goToLastStep (needed for initial load of image)
if (resolutionObj.imageDescription != NULL)
{
//if goes in here, then image description is not null
NSURL *imageURL = [NSURL URLWithString:resolutionObj.imageDescription];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
[resolutionImage setImage:[UIImage imageWithData:imageData]];
}
else
{
//if goes in here, then image description is NULL
//show empty image
[resolutionImage setImage:NULL];
}
}
You are missing a lot the way I see it. If your images are coming from a website then you should use a webView to display it. If you are planning to display images in UIImageView, you should first download them onto your device from the url that points to that image and save it in the sandbox. Then you store the path of this downloaded image in your sqlitedb. Now when you want to load this image you just access this image using the path that you have in your sqlitedb and render it. How do you think by just saving the imageName image013.png and not downloading the image itself will render the image for you in UIImageView. Just think where your UIImageView will go and find this image if it's not already downloaded onto your device. For going and finding on the web directly, you need a UIWebView and not an UIImageView
If you are packaging your images as resources with your app binary, you can load them as shown below:
UIImage *img = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:#"myimagefile" ofType:#"png"]];
[self.testView.imgView setImage:img];
where myimagefile is the name of your file and ofType is the type of image. .png or .jpg or whatever.
If you have anymore doubts. Please come back.

take images from a cell , into next view controller

i asked this question yesterday but it doesnt seem to have asked properly so im trying again
in my app im parsing in an xml file , in that file there is a path for an image to download
an in my tableview controler i have this to download the image and display it in the cell
NSURL *url = [NSURL URLWithString:aStory.picture];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
im then pushing another view controller on the top and displaying some text in a text view , but i also want to take the image from the cell selected and put that in there too , but everything i try does not work.
any ideas on how i can do this
Thanks in advance
Richard
You need to create a property in the target ViewController to hold the image
UIImage *myDownloadedImage;
}
#property (nonatomic, assign) UIImage *myDownloadedImage;
and then when you are about to push you add the image to the controller
myNextViewController.myDownloadedImage = img;
[self.navigationController pushViewController:myNextViewController animated:YES];
Now you have access to the image to do as you wish