I'm trying to load images using the following method.
I first check if I already have the images on the disk, if I do then I will just get the image data from the disk and load it otherwise I will get the image from the server and write to disk so that the second time that I need the image I won't have to access the server.
The problem is it doesn't seem to write or read from the disk. Everytime that I want to load images for the second time it's still reads them from the server and the NSLog(#"disk"); never gets called.
I don't know what I'm doing wrong if anyone has any idea?
-(UIImage *)imageWith:(NSString *)imageName isPreview:(BOOL)preview
{
//imageName is something like "56.jpg"
NSString *mainOrPreview = #"Preview";
if (!preview) {
mainOrPreview = #"Main";
}
NSString *pathSuffix = [[#"Images" stringByAppendingPathComponent:mainOrPreview] stringByAppendingPathComponent:imageName];
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:pathSuffix];
NSData *imageData = [NSData dataWithContentsOfFile:path];
if (imageData) {
NSLog(#"disk");
}
if (!imageData && [self connected]) {
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[serverURL stringByAppendingPathComponent: pathSuffix]]];
if (imageData) {
[imageData writeToFile:path atomically:YES];
}
NSLog(#"server");
}
return [UIImage imageWithData:imageData];
}
The problem is that the directories don't exist beyond Documents. Therefore the attempts to write the files are failing. It's always a good idea to use the file methods that have the NSError parameters so you can check the result.
You need to update only the code that actually writes the image from the server.
if (!imageData && [self connected]) {
// This needs to be done in on a background thread!
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[serverURL stringByAppendingPathComponent: pathSuffix]]];
if (imageData) {
[[NSFileManager defaultManager] createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
[imageData writeToFile:path atomically:YES];
}
NSLog(#"server");
}
Related
I have an UIImage that is getting captured using the device camera, After the image is captured I am saving the UIImage like this,
-(void)onCapture:(UIImage *)image {
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
NSFileManager *filemanager = [NSFileManager defaultManager];
NSString *pathToImage = [NSTemporaryDirectory() stringByAppendingPathComponent:#"my_photo_001.jpg"];
[filemanager createFileAtPath:pathToImage contents:imageData attributes:nil];
NSURL *imageFileUrl = [NSURL fileURLWithPath:pathToImage];
[self.delegate onDone:imageFileUrl];
}
After the NSURL is passed to the delegate the delegate then passes this NSURL to an image editing view controller, I am passing the UIImage as well as the NSURL to the editing view controller, Once someone is done editing I want to override the UIImage stored at the NSURL with the edited UIImage so I am doing this,
NSData *imageData = UIImageJPEGRepresentation(self.editImage.image, 1.0);
NSString *pathToImage = [pathOfCapturedImage absoluteString];
[imageData writeToFile:pathToImage atomically:YES];
NSURL *imageFileUrl = [NSURL URLWithString:pathToImage];
Where pathOfCapturedImage is the variable I am passing to my edit view controller.
However when I am opening the image after saving it opens up the unedited image, Where am I going wrong?
You can try delete the old file first, and the write the new one;
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
First delete old exist image then write on the same path.
NSString* imagePath = #"image path"; // get path of old image.
NSData *imgData = UIImageJPEGRepresentation(self.editImage.image, 1.0); // get data of edited image. please make sure if edited image is not nil.
if ([[NSFileManager defaultManager] fileExistsAtPath:imagePath]) // check existence of old image, If yes then delete it.
{
[[NSFileManager defaultManager] removeItemAtPath:imagePath error:nil];
}
if (imgData)
[imgData writeToFile:imagePath atomically:YES];
NSString *path = dict[#"fileURL"];
NSData *imageData = [NSData dataWithContentsOfFile:path];
imageData is null
dict[#"fileURL"] =
/var/mobile/Containers/Data/Application/0906AB53-CE1F-45EF-8E00-9D0B7C98956C/Documents/ccc/image/1446625127.png
I download the device container and the image did exist.
What's wrong?
It's failed to retrieve your file. Use -dataWithContentsOfFile:options:error: to find why it is failed.
NSError* error = nil;
NSString *path = dict[#"fileURL"];
NSData *data = [NSData dataWithContentsOfFile:path options: 0 error: &error];
if (data == nil)
{
NSLog(#"Failed to read file, error %#", error);
}
else
{
// parse the value
}
I thing you should need to use [NSFileManager defaultManager] to store and fetch the image in your application storage instead of writing static path.
Static path is ok withing the simulator but in the real environment you should need to have the actual path. So [NSFileManager defaultManager] will help you.
if([[NSFileManager defaultManager] fileExistsAtPath:filepath)
{
NSData *data = [[NSFileManager defaultManager] contentsAtPath:filepath];
}
else
{
NSLog(#"File not exits");
}
In filepath you need to pass only your folder and file name. not full path like yours.
IE.
filepath = "Documents/ccc/image/1446625127.png";
NOTE:
This is not a actual answer. This will help you to manage the image into your application storage.
I want to save multiple images to my documents path folder. My web service returns more than one image url path and i want to save each image to my documents folder.This process working successfully, but my view FREEZES at this time(converting image url to NSData).I am using following code.How to avoid this issue?
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[usersArray objectAtIndex:i]objectForKey:#"message"]]];
NSString *localImgpath = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#",imageName, #"png"]];
[data writeToFile:localImgpath atomically:YES];
You would want to process that in a background thread like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[usersArray objectAtIndex:i]objectForKey:#"message"]]];
NSString *localImgpath = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#",imageName, #"png"]];
[data writeToFile:localImgpath atomically:YES];
});
I'm downloading an image and then displaying it with UIImageView. Using this approach the image is downloaded every time the view is loaded. How would I go about storing it locally to avoid an unnecessary server request?
[self requestData ] ;
UIImage *userImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:userProfileImageUrl ]]] ;
[self.profileImageView setImage:userImage ] ;
I would suggest using a library like SDWebImage that handles caching and asynchronous download.
Very first time, you have to save the image into NSDocumentsDirectory. For that you have to take the path of directory and append imageName like this
NSString * documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString * documentsPathAppend = [documentsPath stringByAppendingFormat:#"/%#",[userProfileImageUrl lastPathComponent]];
And you have to write image with folowing condition
if(![[NSFileManager defaultManager]fileExistsAtPath:documentsPathAppend])
{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:userProfileImageUrl]]];
[data writeToFile:documentsPathAppend atomically:YES];
}
After that you have to add this path into your local storage like core data. From next time you have to check whether image is there or not for particular URL in your core data.If it is there, then fetch the path from your core data and show like this
[self.profileImageView setImage:[UIImage imageWithContentsOfFile:imageEntity.imagePath]];
try this method to store UIImage in Local Directory..
- (void)addImage:(UIImage *)image toCacheWithIdentifier:(NSString *)identifier {
NSString *folderPath = #"LOCAL DIRECTORY PATH ";
if(![[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:nil])
{
[[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString *fileName = [NSString stringWithFormat:#"%#.png",identifier];
fileName = [folderPath stringByAppendingPathComponent:fileName];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:fileName atomically:YES];
}
to retrieve image from Local Directory try this method...
- (UIImage *)imageFromCacheWithIdentifier:(NSString *)identifier
{
NSString *folderPath = #"LOCAL DIRECTORY PATH ";
NSString *fileName = [NSString stringWithFormat:#"%#.png",identifier];
fileName = [folderPath stringByAppendingPathComponent:fileName];
if([UIImage imageWithContentsOfFile:fileName])
{
return [UIImage imageWithContentsOfFile:fileName];
}
return nil;
}
One other viable approach is to utilize NSURLCache (see also: Understanding Cache Access) in the official documentation.
The HTTP Cache was invented exactly for this requirement: Caching in HTTP in RFC 2616.
Unfortunately, HTTP Caching is an advanced topic, and the exact behavior of NSURLCache is quite obscure.
I am making an app that downloads files from an online server by clicking an Icon representing the file to be downloaded, then the file will be saved to the app's sandbox.
I have managed to do those mentioned above. Now, what I want to do is to put a "Check" image on the icon to allude the user that it is already downloaded.
I already tried it by putting another UIImageViewon top of the icon when the download is successful but when I fully terminate the app and re-open it, the image is gone and I need to download it again to show it.
How will I able to that?
Just keep an array of all the downloaded files, and at startup check to see which files to apply the check mark to.
For example:
When you get the image:
NSMutableArray *array;
array = [[NSUserDefaults standardUserDefaults] objectForKey:#"downloaded"].mutableCopy;
if (!array) array = [[NSMutableArray alloc] init];
[array addObject:somethingToIdentifyTheImageBy]; //For example, a string with the name of the image
[[NSUserDefaults standardUserDefaults] setObject:array forKey:#"downloaded"]
On startup:
NSArray *downloadedImages = [[NSUserDefaults standardUserDefaults] objectForKey:#"downloaded"];
forin (NSString *string in downloadedImages)
{
//Apply check mark
}
Use following code to Save your Downloaded Image to Library Directory of Device and Retrive it, as NSUserDefaults will not allow you to store Large amount of Data.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libraryDirectory = paths[0];
NSString *imageFilePath = [libraryDirectory stringByAppendingPathComponent:#"myImageIcon.jpg"];
NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:imageFilePath]) {
// File Exist at Library Directory, Just Read it.
NSData *imageData = [NSData dataWithContentsOfFile:imageFilePath];
}
else
{
// File Doesn't Exist at Library Directory, Download it From Server
NSURL *url = [NSURL URLWithString:#"YOUR Image File URL"];
NSData *imageData = [NSData dataWithContentsOfURL:url];
NSString *imagePath = [libraryDirectory stringByAppendingPathComponent:[url lastPathComponent]];
NSLog(#"Image Stored At %#",imagePath);
[imageData writeToFile:imagePath atomically:YES];
}
You cannot save anything inside the app's bundle, but you can store the image in your app's documents directory by using [NSData dataWithContentsOfURL:] method. This is not exactly permanent, but it stays there at least until the user deletes the app.
NSData *imageData = [NSData dataWithContentsOfURL:myImageURL];
NSString *imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"/myImage.png"];
[imageData writeToFile:imagePath atomically:YES];