NSDocumentDirectory files disappear in ios - ios

I want to save a mp4 video in my folder but when I open again the app, this file is nil. But when I save the file, I can open it, so it seems that it disappears from the folder.
Save:
NSData *videoData = [NSData dataWithContentsOfURL:exportUrl];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *tempPath = [documentsDirectory stringByAppendingFormat:#"/%#",videoName];
self.path_video_to_save = tempPath;
BOOL success = [videoData writeToFile:tempPath atomically:YES];
if (success)
NSLog(#"saved");
else
NSLog(#"not saved!!!!!!!!!!!!!!");
I get the success in true so it's ok and I can play my video well.
NSString *path_video = [dict objectForKey:#"path"]; //dictionary where I save the path, the same before and after closing app
NSData *videoData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:path_video]];
if (videoData == nil){
NSLog(#"DATA NULL");
}
else
NSLog(#"DATA OK");
NSLog(#"PATH:%#", path_video);
self.player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:path_video]];
and at this point it work fine.
But when I close and open again the app and I get the path, my app crash and I have the log "DATA NULL" I don't understand why when I close my app the file disappear... what's up?
thanks

This is because in iOS 8 + the name of the Application folder is renamed each time you launch it.
Check it in /Users/"your username"/Library/Developer/CoreSimulator/Devices/"device name"/data/Containers/Data/Application/"application name" (Test in simulator).
So, you have to save the path without the document directory. And when you are trying to retrieve the path you have to add the document directory before the path you saved previously.
Like let your custom folder name is "Save_Video" and file name is "video_01.mp4".
Your file saving path will be "Application document directory"/Save_Video/video_01.mp4
Then you have to store only "Save_Video/video_01.mp4"(in Database/ NSUserDefaults) and when you are retrieving the file the path should be
"Application document directory"/Save_Video/video_01.mp4

Related

STRANGE: Password protected zip file from iCloud changes it's format once backed up, not able to unzip them

I am uploading a password protected zip file as a backup to iCloud, it gets uploaded and then I download, unzip and use the same file, it works perfectly fine only if we are doing all these cool stuffs from the same device.
Consider this scenario,
1. zip and upload the file from one device.
2. download and unzip it from other device (Cannot unzip as it does not recognize that file is in zip format)
Note:
I have cross verified that file gets successfully downloaded in other device by enabling my iTunes file sharing.
But I am not able to unzip the file.
I found the solution by myself hope this will save someone else time, converting password protected zip file into data and uploading, downloading, unzipping the same
Any file can be uploaded to iCloud container of any size (yes you should be having that much of space in iCloud) lets take an example SampleData.zip
// 1 This method will upload or sync SampleData.zip file in iCloud container, iCloud actually checks the metadata of your file before it uploads it into your iCloud container (so for first time it will upload the file and from next time it will only upload the changes)
-(void) iCloudSyncing:(id)sender
{
//Doc dir
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"SampleData.zip"];
NSURL *u = [[NSURL alloc] initFileURLWithPath:filePath];
NSData *data = [[NSData alloc] initWithContentsOfURL:u];
//Get iCloud container URL
NSURL *ubiq = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];// in place of nil you can add your container name
//Create Document dir in iCloud container and upload/sync SampleData.zip
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"]URLByAppendingPathComponent:#"SampleData.zip"];
Mydoc = [[MyDocument alloc] initWithFileURL:ubiquitousPackage];
Mydoc.zipDataContent = data;
[Mydoc saveToURL:[Mydoc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success)
{
if (success)
{
NSLog(#"SampleData.zip: Synced with icloud");
}
else
NSLog(#"SampleData.zip: Syncing FAILED with icloud");
}];
}
// 2 Download data from the iCloud Container
- (IBAction)GetData:(id)sender {
//--------------------------Get data back from iCloud -----------------------------//
id token = [[NSFileManager defaultManager] ubiquityIdentityToken];
if (token == nil)
{
NSLog(#"ICloud Is not LogIn");
}
else
{
NSLog(#"ICloud Is LogIn");
NSError *error = nil;
NSURL *ubiq = [[NSFileManager defaultManager]URLForUbiquityContainerIdentifier:nil];// in place of nil you can add your container name
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"]URLByAppendingPathComponent:#"SampleData.zip"];
BOOL isFileDounloaded = [[NSFileManager defaultManager]startDownloadingUbiquitousItemAtURL:ubiquitousPackage error:&error];
if (isFileDounloaded) {
NSLog(#"%d",isFileDounloaded);
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
//changing the file name as SampleData.zip is already present in doc directory which we have used for upload
NSString* fileName = [NSString stringWithFormat:#"RecSampleData.zip"];
NSString* fileAtPath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSData *dataFile = [NSData dataWithContentsOfURL:ubiquitousPackage];
BOOL fileStatus = [dataFile writeToFile:fileAtPath atomically:NO];
if (fileStatus) {
NSLog(#"success");
}
}
else{
NSLog(#"%d",isFileDounloaded);
}
}
}
//3 voila its done :)

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)

Get Image Path from Images Directory in Supporting Files

I have a bunch of images stored in an images directory within my Supported Files directory in Xcode. I want to be able to show one of those images. What is the best way to obtain a path to that image? Do I have to copy them to the Documents directory first? If so, how can I do that?
EDIT: I've tried the following to copy the image from Supporting Files to the Documents folder in the app. It successfully copies, but I can't get the image to show:
-(void)findImage:(NSString *)imageName
{
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appImagePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.jpg",imageName]];
success = [fileManager fileExistsAtPath:appImagePath];
if (success)
{
return;
}
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultImagePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.jpg",imageName]];
success = [fileManager copyItemAtPath:defaultImagePath toPath:appImagePath error:&error];
if (!success)
{
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
self.imageDisplay.image = [UIImage imageNamed:appImagePath];
return;
}
This should do the trick:
[UIImage imageNamed:#"someImageName"];
EDIT:
Some additional information:
-imageNamed: will look through the entire main bundle of the application for an imagefile (preferrably an png) with the filename of "someImageName". You need not worry about its location or its extension, since it will be searched for in the mainbundle. Files that you import through the import-file-dialogue in xcode will be added to he main bundle.
This means:
If i have imported a file called myImage.png, calling [UIImage imageNamed:#"myImage"];from anywhere in my code will get me a UIImage-Object containing that image. Its amazingly simple, and maybe that startled you a bit ;)
Look it up in the docs if you like:
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIImage_Class/Reference/Reference.html

Proper way of saving and loading pictures

I am making a small app where the user can create a game profile, input some data and a picture that can be taken with the camera.
I save most of that profile data with the help of NSUserDefaults, but a friend discouraged me from saving the profile image in NSUserDefault.
What's the proper way to save and retrieve images locally in my app?
You should save it in Documents or Cache folder. Here is how to do it.
Saving into Documents folder:
NSString* path = [NSHomeDirectory() stringByAppendingString:#"/Documents/myImage.png"];
BOOL ok = [[NSFileManager defaultManager] createFileAtPath:path
contents:nil attributes:nil];
if (!ok)
{
NSLog(#"Error creating file %#", path);
}
else
{
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
[myFileHandle writeData:UIImagePNGRepresentation(yourImage)];
[myFileHandle closeFile];
}
Loading from Documents folder:
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
UIImage* loadedImage = [UIImage imageWithData:[myFileHandle readDataToEndOfFile]];
You can also use UIImageJPEGRepresentation to save your UIImage as a JPEG file. What's more if you want to save it in Cache directory, use:
[NSHomeDirectory() stringByAppendingString:#"/Library/Caches/"]
One way to do this is use the application's document directory. This is specific to a application and will not be visible to other applications.
How to create this:
Just add a static function to App Delegate and use the function where ever the path is required.
- (NSString )applicationDocumentDirectory {
/
Returns the path to the application's documents directory.
*/
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
Hope it Helped..
I think this("iphone-user-defaults-and-uiimages") post addresses your issue. Don't save blobs to a property list such as NSUserDefaults. In your case I would write to disk directly instead.

Resources