How to save images inside app - ios

Hi I'm new to iOS objective c.
I'm working on a app which fetches images and stores it in the app memory for reference.
when u click on the favourite it should go the favourites tab
when clicked on downloads.The image should go on the download tab.
as ALAasset is deprecated can some one explain what is the best way to store images.
is it using file or PHImagemanager.
and how?

You should store images in documents directory something like,
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSString *documentsDirectoryForSaveImages = [docsDir stringByAppendingPathComponent:#"/ProfileImages"];
[[NSFileManager defaultManager] createDirectoryAtPath:documentsDirectoryForSaveImages withIntermediateDirectories:YES attributes:nil error:nil]; // This creates folder in document directory of name "ProfileImages"
Now you can store image something like,
NSData *data = UIImageJPEGRepresentation(responseObject, 1.0); //Convert image to data
[data writeToFile:[documentsDirectoryForSaveImages stringByAppendingPathComponent:formImage] atomically:NO]; //write that data to path. formImage is string value (name of image. Ideally should use timestamp to make unique naming)
You can retrieve image something like,
UIImage *img = [UIImage imageWithContentsOfFile:[documentsDirectoryForSaveImages stringByAppendingPathComponent:formImage]];
Hope this will help :)

Related

QLPreviewController not displays saved file

I'm getting this behaviour using Xcode 8.0. The problem is, after downloading a file and storing it on documents directory (code provided below), QLPreviewController only displays document's name and size. The property currentPreviewItem returns the correct path document. What's even more strange, is that if I try to open that document from another controller in my app, it works fine. I've implemented both QLPreviewControllerDelegate and QLPreviewControllerDataSource.
Code for downloading and saving document:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSURL *url = [NSURL URLWithString:file[#"url"]];
NSData *data = [NSData dataWithContentsOfURL:url];
if (!data) {
completion([NSError new]);
return;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:AppName];
path = [path stringByAppendingPathComponent:file[#"name"]];
file[#"filePath"] = [NSURL fileURLWithPath:path];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil];
completion(nil);
});
});
Then, when user selects a document I use the content saved on #"filePath" to show QLPreviewController. I've tried pushing it and presenting it modally and in both cases it just displays a gray page with document's name and size.
File wasn't showed because downloaded contents didn't contain file's extension. When I tried opening it in other controller, it worked because I temporary used another file name containing the correct extension. So I solved the problem adding the extension .pdf to downloaded files that didn't include it. This made QLViewController displaying correctly the file.
In my case, a file was created with the correct name, but the file contained an error message from the server, thus not representing the expected file structure.

Files saved in <Application_home>/Documents are being lost after a short period of time

I've got an app which saves images (JPEGs) and text files in the app's documents directory. I have tested it in the xcode simulator and on two iPhones (4 and 5, running ios 7.1 and 8.1 respectively), and it works exactly as expected, and the data is preserved fine.
However after submitting it to the app store a user testing the app (using iphone 6, ios 8.1) has found that the saved data is being lost every 20 minutes or so. Does anyone know why this is and how I can solve the issue?
Would marking the files as Do Not Backup solve the issue?
For reference, data being saved in NSUserDefaults is being preserved.
Thanks in advance.
EDIT----
I should have mentioned that I am searching for the documents directory by using:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
self.docsPath = [paths objectAtIndex:0];
I am then appending self.docsPath with the string attributed to the image/file, XXXX.jpg:
self.imgPath = [self.fileName stringByAppendingString:#".jpg"];
self.tempPhotoPath = [self.docsPath stringByAppendingPathComponent:self.imgPath];
I should also clarify that the app functions normally on the iPhone 4/5, unplugged from xcode and running appstore downloaded versions of the app. So far in investigating, it is specifically the iPhone 6 that I am having the problems with, and from what I can tell it is simply clearing the documents directory every 20 minutes or so.
in Apple new documents, whenever app launches every time it generate new sandbox id. So, it you have saved image with full path then it will might lost in second app launch. It will be not showing this effect if you test on simulator or device connected to xcode. Just plug out and run ur app, you can also see this issue your self.
So, instead of save image with its path, just create a folder in Document directory and save your image at there. For path generate you can write below code: (But make sure you save image with a specific id, like imageID and then fetch same image from that imageID).
- (NSString *)documentsPathForFileName:(NSString *)name folder:(NSString*)folderName{
return [[self pathToPatientPhotoFolder:folderName] stringByAppendingPathComponent:name];
}
- (NSString *)pathToPatientPhotoFolder:(NSString *)folderName {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES) lastObject];
NSString *patientPhotoFolder = [documentsDirectory stringByAppendingPathComponent:folderName];
// Create the folder if necessary
BOOL isDir = NO;
NSFileManager *fileManager = [[NSFileManager alloc] init];
if (![fileManager fileExistsAtPath:patientPhotoFolder
isDirectory:&isDir] && isDir == NO) {
[fileManager createDirectoryAtPath:patientPhotoFolder
withIntermediateDirectories:NO
attributes:nil
error:nil];
}
return patientPhotoFolder;
}
NSURL *urla = [NSURL URLWithString:[NSString stringWithFormat:#"%#",[self.imagearray objectAtIndex:indexPath.item]]];// imagearray for array of image url from server
NSString *thumbnailCacheKey = [NSString stringWithFormat:#"thumb-%#",[self.imageIDarray objectAtIndex:indexPath.item]];//first try to check thumb-<my image id> is exist or not.
UIImage *image = [UIImage imageWithContentsOfFile:[self documentsPathForFileName:thumbnailCacheKey folder:#"thumb"]];//this will check thumb-<my image id> in ur sandbox
if (!image){
UIImage *imageToSave = //
NSString *stringPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"thumb"];
// New Folder is your folder name
NSError *error = nil;
if (![[NSFileManager defaultManager] fileExistsAtPath:stringPath])
[[NSFileManager defaultManager] createDirectoryAtPath:stringPath withIntermediateDirectories:NO attributes:nil error:&error];
NSString *filePath = [stringPath stringByAppendingPathComponent:thumbnailCacheKey];
NSData *pngData = UIImageJPEGRepresentation(image, 0.8);
[pngData writeToFile:filePath atomically:YES];
}
else{
yourimageView.image = image;
}

Where to store large files fetched initially in a IOS App

My app downloads at start a sqlite database about 300MB. After the download is done, this sqlite database should be available during the installtime of the app (years :-)) . I don't know where to store this files.
I started to store the data in the library path as follow (swift)
var sDataPath = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true);
No I realize that this path changes during development and testing with the IOS Simulator. Example:
1. I start the app the first time in OIS Simulator. The Evaluated Path is
[/Users/user/Library/Developer/CoreSimulator/Devices/19E2CB7E-3ABB-4C0A-8B49-39A0BE392A93/data/Containers/Data/Application/5EE51B55-0A89-45FB-A1E2-9BE3DCD33463/Library]
2. The App downloads the data. This takes some minutes.
3. I close the simulator and restart also xcode
4. I start the app again in the simulator and expect to have the already downloaded data in my apps' library path. But no ...
5. the app evaluates a new path, which has another ID in the Path:
[/Users/user/Library/Developer/CoreSimulator/Devices/19E2CB7E-3ABB-4C0A-8B49-39A0BE392A93/data/Containers/Data/Application/429206E9-00EA-45EF-BE6E-4B2E9374BAF5/Library]
6. And the app downloads the content again.
I would like to have a static path over the lifetime of the device. What am I doing wrong or what should I change ?
The path is changing on the simulator but it will be the same on a real device.
If I'm not wrong, on the simulator the path change every time you restart it. On a device the path will change only if you delete and reinstall your application.
You should save downloaded image to document directory. In this way images can load fastly. If u want to overcome of reloading cell then you have to check for then file path whether is fill is there or not.
- (NSString *)documentsPathForFileName:(NSString *)name folder:(NSString*)folderName{
return [[self pathToPatientPhotoFolder:folderName] stringByAppendingPathComponent:name];
}
- (NSString *)pathToPatientPhotoFolder:(NSString *)folderName {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES) lastObject];
NSString *patientPhotoFolder = [documentsDirectory stringByAppendingPathComponent:folderName];
// Create the folder if necessary
BOOL isDir = NO;
NSFileManager *fileManager = [[NSFileManager alloc] init];
if (![fileManager fileExistsAtPath:patientPhotoFolder
isDirectory:&isDir] && isDir == NO) {
[fileManager createDirectoryAtPath:patientPhotoFolder
withIntermediateDirectories:NO
attributes:nil
error:nil];
}
return patientPhotoFolder;
}
in your cellForRowAtIndexPath: method
{…..
NSURL *urla = [NSURL URLWithString:[NSString stringWithFormat:#"%#",[self.imagearray objectAtIndex:indexPath.item]]];
NSString *thumbnailCacheKey = [NSString stringWithFormat:#"thumb-%#",[self.imageIDarray objectAtIndex:indexPath.item]];;
UIImage *image = [UIImage imageWithContentsOfFile:[self documentsPathForFileName:thumbnailCacheKey folder:#"thumb"]];
if (!image){
//first download image here and then save that image like:
NSString *stringPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"thumb"];
// New Folder is your folder name
NSError *error = nil;
if (![[NSFileManager defaultManager] fileExistsAtPath:stringPath])
[[NSFileManager defaultManager] createDirectoryAtPath:stringPath withIntermediateDirectories:NO attributes:nil error:&error];
NSString *filePath = [stringPath stringByAppendingPathComponent:thumbnailCacheKey];
NSData *pngData = UIImageJPEGRepresentation(image, 0.8);
[pngData writeToFile:filePath atomically:YES];
}
else{// image is already downloaded, so just set that image
cell.imageView.image = image;
}
….
}
This code creates folder in your DocumentDirectory and save image there and fetch from there. I save with one unique photoID so that image can not be same. You can save with your requirement.
You should store it on Cache folder.
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *cacheFile = [cachesPath stringByAppendingPathComponent:#"file.plist"];
Store large file in other directory will be rejected by apple app review team (as i have faced)

Lost data after store and reload of UIImage in iPhone App

I have developed an iOS7 app. I use the UIImagePickerController to get a UIImage. During the usage of the app an image
is stored to the local app directory and loaded. The file will be overwritten several times. I use UIImagePNGRepresentation and NSData storeToFile to store
the picture. In order to load the image I use UIImage initWithContentsOfFile.
It works fine for some store and load processes. With the Debugger I can confirm that the picture is stored and loaded appropriately.
But after some time the stored picture does not contain a picture anymore. When I look at the load procedure with the debugger I can see that
a picture is loaded but it seems to be completely transparent with no other information.
This phenomenon only occurs on a device and not during a simulation with the simulator. Furthermore, the effect seems to occur only when the app is kicked out of the memory (double tap of the home button)
I debugged the app for hours but I cannot imagine the reasons for this behaviour. Additionally it is difficult to debug due to the complete termination of the app. Does anybody know a solution or has been faced with the same problem? Could anybody give me a hint what to debug to track down the problem?
Thanks in advance. Any help is appreciated. :)
Thanks for your answers. Here is a code excerpt:
Code to store image:
Generate file path in documents directory
NSString *name = [NSString stringWithFormat:#"ImageforButton%i.png",i];
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *file = [[path objectAtIndex:0] stringByAppendingPathComponent:name];
Create NSData from UIImage (image is a UIImage that always has the correct image data)
NSData *picData = UIImagePNGRepresentation(image);
Write NSData to file
[picData writeToFile:file atomically:true];
Code to load image:
Generate file path
NSString *name = [NSString stringWithFormat:#"ImageforButton%i.png",i];
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *file = [[path objectAtIndex:0] stringByAppendingPathComponent:name];
Load picture
UIImage *img;
if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:false] == true)
{
img = [UIImage imageWithContentsOfFile:[self saveFilePath:name]];
}
img does not always contain the right data. Before the app is completely terminated img
contains the expected picture. After the app was completely terminated a valid
UIImage can be loaded to img but it seems only to contain a transparent picture.
All in all it does not contain the right picture anymore.

Save image path to sqlite3 database

I am having some troubles saving images path into Documents folder and store the path into my sqlite3 local db.
Today I successfully stored the images as BLOB into the db, but reading around the Internet, people said that this is not recommended.
So, now I'm trying to store image path in DB but..
Situation
User taps a button to choose an image (via UIImagePickerView) or take a new photo
After choosing the image, an imageView is set with the image chosen.
Code for picker:
-(void)imagePickerController:(UIImagePickerController *)pickr didFinishPickingMediaWithInfo:(NSDictionary *)info{
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
/* Test code for saving data */
//NSString *dir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
//NSString *pngPath = [NSString stringWithFormat:#"%#/test.png",dir];
//NSData *data = [NSData dataWithData:UIImagePNGRepresentation(image)];
//[data writeToFile:pngPath atomically:YES];
[imageView setImage:image];
picture = YES;
[pickr dismissModalViewControllerAnimated:YES];
}
Now I got a couple of questions
Into my db, image is BLOB type. Should I edit it to TEXT?
How is the path saved? I mean, in the test code /test.png is a generic image name. Does the chosen image name get saved too so that I can retrieve it? Or, better, if I save an image picked from my library with name "IMG0001", does it get saved as "test"?
What's the right way to save an image into documents folder, its path to the DB and then retrieve it?
I googled a lot to find an answer, but after experimenting a lot I gave up.
Thanks in advance
Here is nice tutorial on how to save images in Documents directory
You need to convert your BLOB field to TEXT field and just save file name of that image. You can also create folder in Documents directory and then access by foldername/filename.png.
Hope this information helps you..
EDIT
Here is code to check if that folder exits, If not exist create new that folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentsDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"MyFolder"];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]){
NSError* error;
if( [[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error])
;// success
else
{
NSLog(#"[%#] ERROR: attempting to write create MyFolder directory", [self class]);
NSAssert( FALSE, #"Failed to create directory maybe out of disk space?");
}
}
You cannot directly access the image from the user's photo library, since you have access only to your Applications Sandbox folder.
So if you don't want to store the image as a blob file in the database, you should save the image in the caches folder inside your App's documents folder and then store the filename you set to the image in the database.
Since all images are going to be in the same path folder, you don't need to actually save the entire path in the database, but only the filename should be sufficient enough.

Resources