Saving images from web server to phone for image slider - ios

I have an app where it pulls urls of images from a database and stores it in coredata. Then in my app view, there's a scrollview of imageviews, basically I'm trying to do an image slider. These images tend to get updated so it needs to load from the server. I load the image urls from the coredata, download them to uiimages and load them in my view. Problem is, it's really slow as I'm doing it at runtime.
I was wondering what's the best way to go about this. I was thinking of loading all the images to the phone first when the app launches? I tried looking for some sample code to point me to the right direction but I can only find code that saves images to the phone's camera roll and not to the app itself. Anyone could help pls? Thanks!

Here's a method that takes a UIImage, a target path (the directory you want to save the image to) and the filename for the image, and saves the image as a PNG file:
-(BOOL) saveImage:(UIImage *)image savePath:(NSString *)savePath filename:(NSString *)filename{
savePath = [savePath stringByAppendingPathComponent:filename];
NSData *sourceData = UIImagePNGRepresentation(image);
return [sourceData writeToFile:savePath atomically:YES];
}
You will need to store the image in the right location within the app's sandbox. For example, don't put them in the Documents folder as it may be rejected by Apple since you can recreate (or re-download) the images. You likely want to put them in the Library/Caches folder, and be prepared to re-download them if they are removed. See the iOS File System Programming Guide for details on this.
I would be concerned about downloading all the files at app start, since it will look like the app has frozen if it non-responsive while download a number of image files. You can download the images in the background and update the UI as the images finish downloading.
One method to do this would be to check if the image has already been downloaded (e.g., is it in the Library/Caches folder). If it is, then use it, otherwise use a placeholder image until the image is downloaded. For example:
if (isImageAvailable) {
displayedImageView.image = cachedImage;
} else {
displayedImageView.image = placeholderImage;
[self getImageAtURL:imageURL andThenDo:^(UIImage *image) {
// Replace placeholder image with downloaded image
displayedImageView.image = image;
}];
}
Replace isImageAvailable with a method that checks for the existence of the image file in the Library/Caches folder. displayedImageView is the UIImageView you are displaying the image with.
The getImageAtURL method would look something like:
-(void)getImageAtURL:(NSURL *)url andThenDo:(void(^)(UIImage *image))completionBlock{
// Run on background thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *image;
// Insert code to download image...
// Switch to main (UI) thread to allow updating the UI
dispatch_sync(dispatch_get_main_queue(), ^{
completionBlock(image);
});
});
}

You might not need to download images to your application, I can suggest better you use image url it self to load images from server it self.
To load images from server u may use following:
UIImage* yourImageview = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:your.image_url]]];
Downloading all images will also slow down your app.

Related

How to put my url images into carousel?

I am getting URL images from API. I have stored the UR images into string. Here my problem I want to display that into carousel. I don't know how to do this. Below is my code that I have tried.
for(int i=0;i<hotelIMAges.count;i++ )
{
NSDictionary *images=[hotelIMAges objectAtIndex:i];
NSString *Images= [images objectForKey:#"Imagepath"];
[ImageARRAy addObject:Images];
} //Here I have stored all the images into string..(https://***.jpg)
Carousel *carousel = [[Carousel alloc] initWithFrame:CGRectMake(0, 0,300, 262)];
[carousel setImages:ImagesARRAy];
You just need to process asynchronously as your current approach can be a synchronous request and blocks the main thread until that download is complete.
Consider using SDWebImage and the UIImageView extension it adds to manage the image download and display. It also supports a placeholder image that you can supply to indicate that the download is in progress.
If your using any third party carousel check for asynchronous methods to display the images.I believe setImages: method must be for images that are stored locally inside app. Do let me know if you have any queries.
----EDITED----
Your Carousel is using synchronous method to display which blocks the main thread.
You can use SDWebImage for your purpose.
For this you need to download SDWebImage for asynchronous downloading of image. You can download SDWebImage from link below.
You can use it in your Carousel.h class as
#import <SDWebImage/UIImageView+WebCache.h>
modify your setup method with below line.
[imageView sd_setImageWithURL:[NSURL URLWithString:self.images[i]]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
For details refer github page of SDwebpage. DO let me know if you have any queries.
https://github.com/rs/SDWebImage#using-asynchronous-image-downloader-independently

iOS UITableViewCell Images from URL

I am loading images in my UITableViewCell from some web url and those images are in size around 80-100 kb per image. Everything works fine when i download images asynchronously but when i scroll the tableview, images start again downloading. Can i get rid of this as i have only limited no of rows.
I want if images from url download once should not be download again as it does makes view not comfortable for users when images starts downloading again.
I am using below code to load images in CellforRowAtIndexPath:
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:url];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^{
cell.eventImage.image= [UIImage imageWithData:data];
});
});
You should use SDWebImage which will cache image on your device and if same image came from server then it load from your local device.
Add SDWebImage to your project.
import <SDWebImage/UIImageView+WebCache.h> header
then add below code at cellForItemAtIndexPath:
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:#"your image URL"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
Better make use of SDWebImageCache for this because this a advantageous third party library to store the image in cache. After downloading once the images will be taken automatically from the cache.
SDWebImageCache
When you Download image put it to the document directory and before you download image check if document directory contains image then load it from there otherwise download from URL
If you want you can make it yourself. You can use NSCache in order to save your images. NSCache it is like NSMutableDictionary (save your image by key). And then you can check it. For key you can use path to your image.
But I also recommend you to use SDWebImage.

Getting so much load while displaying image from document directory folder iOS

I am displaying images in UITableview from document directory folder but it's getting so much loading, how can I make it smooth. See below my code:
cell.imageView.image = [UIImage imageWithContentsOfFile:path];
If I convert the path into NSData then it also get so much load to display image in UITableview.
Any suggestion or any other way to display the image from document directory or any suggestion for smoothly loading images from document directory?
Try LazyTableImages sample code from Apple like Phil Kulak answered to a similar question.

How to store images and refere to it for my iOS interface?

I'm using XCode 6.
Let's say I have a Food model containing a (UIImage *)image property. I would like to display all my foods displaying images for my interface.
I have already the pictures for the foods (they are not in the Photo Library of the device but on my computer).
1) Where to put these image files (beet.png, banana.png etc... for example) in Xcode ? (is there a dedicated folder ?)
2) How to refere to this image file ? Example in my Food class, self.image = ?
Thanks a lot !
You can just drag and drop image files to your project while xcode is open.
make sure you use copy items if needed option, it is less hassle.
once you clikc finish for your files, you will see your files on bundle.
then all you need to do is call
[UIImage imageNamed:#"imageInBundle.png"];
imageNamed: will search your main bundle
or long way
NSBundle* bundle = [NSBundle bundleWithURL:[[NSBundle mainBundle]URLForResource:#"YourBundle" withExtension:#"bundle"]];
NSString *imagePath = [bundle pathForResource:#"imageInBundle" ofType:#"png"];
UIImage* image = [UIImage imageWithContentsOfFile:imagePath];
1) you can create new group inside your project in XCode and drag images to it. Check in build phases, in Copy Bundle Resources to make sure they'll be copyed in final app. 2) you refer image using imageWithName. You can use UIImageView for easier management and set this image your imageWithName. Otherwise you can implement directly images in your xib. Anyway how do you want to use images? In a table, in a collection, in a detail view? Depends on you how you want to display them and how you manage to make things work.

Loading images into memory in iPhone App

I have an UImageView and on click of an button i want to change the UImage in the UImageView. App has 22 UImages with each image exceeding 5 mb size , so the UImageView takes some time to load an image when the button is clicked , is there a way by which we can load these images into the memory so that image view takes lesser time to show the image?
I use the following code to set the image :
[ImageView setImage:[UIImage imageNamed:#"ImageName.jpg"]];
basically i want on swipe the images to be changed , e.g. if a user swipes from right to left the app must show the next image and on left to right click the back image be loaded . please suggest .
like #Gobot mentioned it is the best way du reduce the size of your pictures. For the swipe there is no need to use big pictures like this. You could just create two folders, one with small sized pictures and another with bigger one. If you swipe through, you just use the small pictures. If a user taps a picture you could get the name of the selected UIImage and load just this single picture. That way you also can provide high quality pictures for zooming in. And keep in mind, that your app package gets also bigger the more pictures you have included.
There is a good explanation in a WWDC Stream: iOS App Performance: Graphics and Animations
I also created a method inside a NSMutableArray category for loading all my UIImages once. You could use this method inside viewDidLoad:
- (NSMutableArray *)getImagesWithStartSuffix:(NSString *)start
andEndSuffix:(NSString *)end{
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
for (int i = 1; i < 100 + 2; i++) {
NSString *fileName = [NSString stringWithFormat:#"%#%d%#.jpg",
start, i, end];
if([self fileExistsInProject:fileName]){
[imageArray addObject:[UIImage imageNamed:fileName]];
} else {
break;
}
}
return imageArray;
}
There is also a very easy way to change the size of your pictures by writing an Apple Script. You could run a loop over all pictures and resize them all this way. This is the easiest way and you don't have to use any tools like Gimp or PS:
do shell script "sips [path_to_file]/picture1.jpg -z 666 1000 --out [path]/changedSize/picture1_small.jpg"
From the Documentation:
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.
if it takes too long, you may want to add a progress indicator in your app till the full view is generated/loaded then display it on your screen.
The first and simplest option would be to reduce your images under 5MB. Do they really need to be that big? Are they thumbnails? The more complex option would be to load/cache images in a background thread (asynchronously) using dispatch queues.

Resources