Simple question regarding data persistance between application sessions.
My application allows the user to select an image from the Library using a UIImagePickerController. The selected photo is then used as the background to the application.
As the UIImagePickerController delegate method actually returns an image as opposed to an image path, I am wondering what is the best way to persist this image over user sessions?
I do not require any other data to be persisted at the moment, as everything else is pulled in from SQL Server, but I do not want the added overhead of having to store the image in the server as well, which would mean that everytime the user opened the application the background image would first have to be downloaded from the server into a byte array and then converted into an image.
I have found the following code that can save the image:
- (void)saveImage:(UIImage *)image withName:(NSString *)name {
//save image
NSData *data = UIImageJPEGRepresentation(image, 1.0);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
[fileManager createFileAtPath:fullPath contents:data attributes:nil];
}
I am not on a mac at the moment, so I cannot test this code, but I have a couple of questions regarding the code above:
I don't want a lot of files cluttering the file system. So I would like a single background file (background.png); how would the code above handle a situation where this file already existed?
Would it overwrite the existing file or would it throw an error?
How would I go about loading the image again?
You have to remove the file first:
- (void)saveImage:(UIImage *)image withName:(NSString *)name {
//save image
NSData *data = UIImageJPEGRepresentation(image, 1.0);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
NSError *error = nil;
if( [fileManager fileExistsAtPath:fullPath] ){
if( ! [fileManager removeItemAtPath:fullPath error:&error] ) {
NSLog(#"Failed deleting background image file %#", error);
// the write below should fail. Add your own flag and check below.
}
}
[data writeToFile:fullPath atomically:YES];
}
Reading back in should work as follows:
...
UIImage *bgImage = [UIImage imageWithContentsOfFile:fullPath];
...
Related
I am working on a application that is a sort of video recorder, but i'm facing a problem, while coredata could support keeping data on migration (install uppdate, reinstall program), applications files save to the document folder of the app are deleted. I'm using a webservice for some images, but all the video recorded by the user are lost.
Is there a way to keep application local files (in the document folder) while migrating (like relaunching the app from xcode without deleting it on the phone) ?
I'm talking about path like :
filePath NSString * #"/var/mobile/Containers/Data/Application/7FB440BB-76DD-49C6-B5DD-AA9D26A86C51/Documents/dataImage/image_1_maquette_miniature.jpg" 0x000000015c528520
EDIT :
I've found that, when i rebuild my app:
/var/mobile/Containers/Data/Application/509E8B5D-A3C4-4D90-809B-47159AC60542/Documents/dataImage/image_1_gabarit_masque.png
/var/mobile/Containers/Data/Application/660EF541-CDD0-439C-BCAB-B7FE4371799A/Documents/dataImage/image_1_gabarit_masque.png
The UUID changes so here is my code to write files:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if(![self createFolderIfNoExists:#"dataImage"]) {
fileManager = nil;
return nil;
}
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"dataImage/image_%d_%#.%#",objectID,assetTypeName,extension]];
if ([fileManager fileExistsAtPath:filePath] == YES) {
[fileManager removeItemAtPath:filePath error:nil];
NSLog(#"DELETE file exists %d",[fileManager fileExistsAtPath:filePath]);
}
if([imageData writeToFile:filePath atomically:NO] == NO) {
NSLog(#"[Error] Create File %# at %#", imageData,filePath);
fileManager = nil;
return nil;
}
The following code works without error or exception - but still, it does not do what it should ! I wanted to save an image into the iOS library/Application Support folder. More precisely, the image should be placed into a /library/Application Support/bundleID_name/subfolder/ (and the subfolder being called "location1").
If I check the functionality with the iOS-Simulator, I can see the creation of the subfolder (i.e. .../library/Application Support/bundleID_name/location1/). Also the function "saveImage" works without exception. But there is no image being saved !!!! (i.e.the image-file is missing and the folder remains empty) !!
What could be the mistake ??
Here is my code with the call of two functions (see code below):
UIImage *in_image = [UIImage imageNamed:#"template009c.jpg"];
NSString *locDirectoryName = #"location1";
NSURL *LocationDirectory = [self appendLocationToApplicationDirectory:locDirectoryName];
[self saveImage:in_image :#"image1" :LocationDirectory];
With the corresponding function-Nr1:
- (NSURL*)appendLocationToApplicationDirectory:(NSString*)locationDirName
{
NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
NSFileManager*fm = [NSFileManager defaultManager];
NSURL* dirPath = nil;
// Find the application support directory in the home directory.
NSArray* appSupportDir = [fm URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask];
if ([appSupportDir count] > 0) {
// Append the bundle ID and the location-Foldername to the URL for the Application Support directory
dirPath = [[[appSupportDir objectAtIndex:0] URLByAppendingPathComponent:appBundleID] URLByAppendingPathComponent:locationDirName];
// If the directory does not exist, this method creates it.
// This method call works in OS X 10.7 and later only.
NSError* theError = nil;
if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES attributes:nil error:&theError]) {
// Handle the error.
NSLog(#"%#", theError.localizedDescription);
return nil;
}
else {
// Mark the directory as excluded from iCloud backups
if (![dirPath setResourceValue:#YES
forKey:NSURLIsExcludedFromBackupKey
error:&theError]) {
NSLog(#"Error excluding %# from iCloud backup %#", [dirPath lastPathComponent], theError.localizedDescription);
}
else {
NSLog(#"Location Directory excluded from iClud backups");
}
}
}
return dirPath;
}
And function Nr2:
//saving an image
- (void)saveImage:(UIImage*)image :(NSString*)imageName :(NSURL*)pathName {
NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format.
NSFileManager *fileManager = [NSFileManager defaultManager];
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *LocationDirectory = [pathName absoluteString];
NSString *fullPath = [LocationDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", imageName]];
/***** THE FOLLOWING LINE DOES NOT SEEM TO DO WHAT IT IS SUPPOSED TO *******/
[fileManager createFileAtPath:fullPath contents:imageData attributes:nil];
/**** I also tried without the FileManager, but same problem - no file written... ***/
// [imageData writeToFile:fullPath atomically:NO];
NSLog(#"image saved");
}
By the way, getting the "fullPath" with the XCode-Debugger, I get:
"fullPath NSPathStore2 * #"file:/Users/username/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/2BCC3345-9M55F-4580-A1E7-6694E33456777/Library/Application%20Support/bundleID_name/image1.png" 0x09d50950
Doesn't that also seem correct ?? But why is [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; not performing ???
This:
"fullPath NSPathStore2 * #"file:/Users/username/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/2BCC3345-9M55F-4580-A1E7-6694E33456777/Library/Application%20Support/bundleID_name/image1.png" 0x09d50950
is not a valid path, it's a URL path but stored in a string. If you are going to use URL's then use ULRs rather than trying to convert to a string:
[imageData writeToURL:pathName atomically:YES];
(preferably naming the parameter as pathURL) and if you want to use paths then don't use a URL at any stage.
Also, where an API method returns an error or status flag, check it in the code as standard.
I'm pretty sure you can't save an image on a path you specify. You can save images on the gallery or in DocumentDirectory. This should be the code to save an image on the DocumentDirectory:
NSString *imgName=[#"imgname.png"];
[[NSUserDefaults standardUserDefaults]setValue:imgName forKey:#"imageName"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:imgName];
UIImage *image = imageView.image; // imageView is my image from camera
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
I am trying to save images to my apps documents directory. While I am easily able to save the images to the directory, its taking about two seconds to save an image and its thumbnail. I am using the following methods to save the images using a queue.
+ (void)saveImage:(UIImage*)imageToSave withName:(NSString*)imageName toFolder:(NSString*)folderName
{
[Utils createFolderWithPath:folderName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#/%#.png",folderName,imageName]];
NSData *imageData = UIImagePNGRepresentation(imageToSave);
[imageData writeToFile:savedImagePath atomically:NO];
}
+ (void)createFolderWithPath:(NSString *)folderPath
{
NSError *error = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:folderPath];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
[[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:NO attributes:nil error:&error];
}
}
is there a faster way? Since I have to save multiple images and 2 seconds per image is a lot of time!
You dont need to find the document directory every time. Just find out it one time and store it. and run your code in a thread, thread will save the image in background.
I am trying to work out how to manage files and directories in my app's Documents folder. I have been trying to make sense of the NSData class but without joy. I have managed to write an image to my Documents folder using the following code.
- (IBAction)writeImage:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.png"];
UIImage *image = [UIImage imageNamed:#"Default.png"];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}
What I would like to know is how to create and delete directories and files. Can anyone point me to correct place to look? Thanks in advance.
For folder you can use:
[[NSFileManager defaultManager] createDirectoryAtURL:folder withIntermediateDirectories:YES attributes:nil error:&error];
It will create all folders at given path which is cool :)
The NSFileManager class enables you to perform many generic file-system operations and insulates an app from the underlying file system.
There is a class method in NSFileManager class called +defaultManager which always gives you same FileManager object or shared Object and most file operations can be performed using this shared file manager object.
You can write by avoiding overwriting your file if it already exists as below and can also check if the folder is writable or not.
NSString *imageName = #"Default.png";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
NSString *savedImagePath = [NSString stringWithFormat:#"%#/%#", documentsDirectoryPath, imageName];
// Write only if file does not exist.
if (![[NSFileManager defaultManager] fileExistsAtPath:savedImagePath]) {
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}
// Check if folder is writable
NSString *folderPath = #"someFolderPath";
if ([[NSFileManager defaultManager] isWritableFileAtPath:folderPath]) {
NSLog(#"Folder is writable");
}else {
NSLog(#"Folder is not writable");
}
I want to delete an image from my iPhone app.
I use the method below, passing the name of the image as an argument.
The problem is that the image isn't deleted.
- (void)removeImage:(NSString*)fileName {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"%#.png", fileName]];
[fileManager removeItemAtPath: fullPath error:NULL];
NSLog(#"image removed: %#", fullPath);
NSString *appFolderPath = [[NSBundle mainBundle] resourcePath];
NSLog(#"Directory Contents:\n%#", [fileManager directoryContentsAtPath: appFolderPath]);
}
The last two lines show the content in my app directory and the image I want to delete is still there. What am I doing wrong?
You are trying to delete a file in the Documents directory. You then read the contents of the bundle resources directory. These are not the same directory.
If you're trying to delete a file in the Documents directory, the you should rad that directory in your NSLog() at the end. If you're trying to delete a file inside your bundle, this is impossible. App bundles are signed and cannot be modified.
your code looks ok, so try adding some 'NSError' object to you code:
- (void)removeImage:(NSString*)fileName {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"%#.png", fileName]];
NSError *error = nil;
if(![fileManager removeItemAtPath: fullPath error:&error]) {
NSLog(#"Delete failed:%#", error);
} else {
NSLog(#"image removed: %#", fullPath);
}
NSString *appFolderPath = [[NSBundle mainBundle] resourcePath];
NSLog(#"Directory Contents:\n%#", [fileManager directoryContentsAtPath: appFolderPath]);
}
In the code above I passed a NSError the error parameter of removeItemAtPath. If the system can't delete the file, this method will return NO and fill the error object with the error raised.
Based on your comment I found out that you are trying to delete the default.png and replace it with another one. Unfortunately, this is impossible. The image default.png is a part of your application bundle, which cannot be modified once it has been created and signed (this is a security measure from Apple, so applications cannot change after they have been reviewed). The only locations where you can create and delete files is inside the sandbox given to your application (the Documents folder).