Saving and retrieving files from a folder in documents directory IOS - ios

I am trying to save and retrieve a file from a folder in the documents directory. I retrieve it in this way:
NSFileManager *fManager = [NSFileManager defaultManager];
NSString *item;
NSString *docsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSArray *contents = [fManager contentsOfDirectoryAtPath:[NSString stringWithFormat:#"%#", docsPath] error:nil];
and save it like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* BusinessCardPath = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:#"BusinessCard%lld.card", arc4random() % 100000000000000]];
For some reason if I do:
NSArray *contents = [fManager contentsOfDirectoryAtPath:[NSString stringWithFormat:#"%#/FOLDER", docsPath] error:nil];
and
NSString* BusinessCardPath = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:#"FOLDER/BusinessCard%lld.card", FolderNumber, arc4random() % 100000000000000]];
It doesn't open or show the file, but when I log the two it shows the same directory. Is this how you use folders in IOS? Please help, i'm going crazyyyy!!

I guess you use the NSFileManager for nothing. it's confusing how you store and use your data.
Here's a class you could use to load, store and delete data into the NSDocumentDirectory:
DKStoreManager.h
#interface DKStoreManager : NSObject
+ (NSArray *)loadBusinessCardContentForKey:(NSString *)key;
+ (void)storeBusinessCardContent:(NSArray *)content forKey:(NSString *)key;
+ (void)removeBusinessCardForKey:(NSString *)key;
#end
DKStoreManager.m
#interface DKStoreManager () {
NSString * _rootPath;
}
#end
#implementation DKStoreManager
- (id)init {
self = [super init];
if (self) {
// get the root path of the Document Directory
// NSCacheDirectory is also good to use
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
_rootPath = [paths objectAtIndex:0];
}
return self;
}
+ (DKStoreManager *)sharedInstance {
static DKStoreManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[DKStoreManager alloc] init];
});
return sharedInstance;
}
#pragma mark - storing management methods
// store a data into a file in a specific sub directory
- (id)storeObject:(id)object inFile:(NSString *)filename inDirectory:(NSString *)directory {
NSString *fullPath = [_rootPath stringByAppendingPathComponent:directory];
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath])
[[NSFileManager defaultManager] createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
fullPath = [fullPath stringByAppendingPathComponent:filename];
BOOL result = [NSKeyedArchiver archiveRootObject:object toFile:fullPath];
if (result)
NSLog(#"Successfully saved %#/%#", directory, filename);
else
NSLog(#"ERROR: can't save %#/%#", directory, filename);
return (result ? object : nil);
}
// remove a file in a specific sub directory
- (void)removeFile:(NSString *)filename inDirectory:(NSString *)directory {
NSString *fullPath = [_rootPath stringByAppendingPathComponent:directory];
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath])
return ;
fullPath = [fullPath stringByAppendingPathComponent:filename];
NSError *error = [NSError new];
if ([[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error])
NSLog(#"Successfully removed %#/%#", directory, filename);
else
NSLog(#"ERROR: can't remove %#/%# : %#", directory, filename, [error localizedDescription]);
}
// get the data stored into a file
- (id)loadObjectInFile:(NSString *)filename inDirectory:(NSString *)directory {
NSString *fullPath = [_rootPath stringByAppendingPathComponent:directory];
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath])
return nil;
fullPath = [fullPath stringByAppendingPathComponent:filename];
return [NSKeyedUnarchiver unarchiveObjectWithFile:fullPath];
}
#pragma mark - business cards methods
+ (NSArray *)loadBusinessCardContentForKey:(NSString *)key {
DKStoreManager *storeManager = [DKStoreManager sharedInstance];
return [storeManager loadObjectInFile:key inDirectory:#"business_cards"];
}
+ (void)storeBusinessCardContent:(NSArray *)content forKey:(NSString *)key {
DKStoreManager *storeManager = [DKStoreManager sharedInstance];
[storeManager storeObject:content inFile:key inDirectory:#"business_cards"];
}
+ (void)removeBusinessCardForKey:(NSString *)key {
DKStoreManager *storeManager = [DKStoreManager sharedInstance];
[storeManager removeFile:key inDirectory:#"business_cards"];
}
#end
I don't really understand what you want to do but a good way to use this class could be:
NSArray *contents = [DKStoreManager loadBusinessCardContentForKey:aBusinessCard.name];
[DKStoreManager storeBusinessCardContent:aContent forKey:aBusinessCard.name];
[DKStoreManager removeBusinessCardForKey:aBusinessCard.name];
By the way you can store any data/object you want with this class: NSArray, NSDictionnary,... and even your own class the only thing you need to do is to implement the NSCoding protocol

Related

Data storing issue into plist file

Once plist is created data storing start automatically, but after some time it automatically stop storing data in plist. But once when i kill app and restart again, it will start again as previously mention and cycle goes on...
Here is my code
- (void)saveLocationsToPlist:(NSMutableDictionary*)mdictPlist {
NSString *plistName = [NSString stringWithFormat:#"LocationArray.plist"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *fullPath = [NSString stringWithFormat:#"%#/%#", docDir, plistName];
NSMutableDictionary *savedProfile = [[NSMutableDictionary alloc] initWithContentsOfFile:fullPath];
NSLog(#"ADD LOCATION TIME : %#",[NSDate date]);
NSLog(#"ADD LOCATION DATA : %#",mdictPlist);
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]){
BFLog(#"applicationDocumentsDir Not exists");
fullPath = [docDir stringByAppendingPathComponent: [NSString stringWithFormat:#"LocationArray.plist"] ];
}
if (!savedProfile) {
savedProfile = [[NSMutableDictionary alloc] init];
self.myLocationArrayInPlist = [[NSMutableArray alloc]init];
} else {
self.myLocationArrayInPlist = [savedProfile objectForKey:#"LocationArray"];
}
if(mdictPlist) {
if(self.myLocationArrayInPlist == nil){
self.myLocationArrayInPlist = [[NSMutableArray alloc]init];
}
[_myLocationArrayInPlist addObject:mdictPlist];
[savedProfile setObject:_myLocationArrayInPlist forKey:#"LocationArray"];
}
if (![savedProfile writeToFile:fullPath atomically:FALSE]) {
BFLog(#"Couldn't save LocationArray.plist savedProfile :- %# \n Location Data :- %# \n fullPath:-%#",savedProfile,mdictPlist,fullPath);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
NSFileManager *fm = [NSFileManager defaultManager];
NSString *directory = [documentsDirectoryPath stringByAppendingPathComponent:#""];
NSError *error = nil;
for (NSString *file in [fm contentsOfDirectoryAtPath:directory error:&error]) {
NSLog(#"%#",[NSString stringWithFormat:#"%#/%#", directory, file]);
if([file isEqualToString:#"LocationArray.plist"]){
BOOL success = [fm removeItemAtPath:[NSString stringWithFormat:#"%#/%#", directory, file] error:&error];
if (!success || error) {
// it failed.
BFLog(#"Delete error : %#",error);
}
else {
[self saveLocationsToPlist:myLocationDictInPlist];
}
}
}
}
}
Any idea about this issue.

how to find subfolder in an existing folder in iOS

My folder contains only one sub-folder, and I don't know sub-folder's name. This sub-folder contains a html file, and once again I don't know the html file's name.
My question is how I can get full path of this file by using
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *folderPath = [documentsDirectory stringByAppendingPathComponent:filename];
//- access sub-folder?
//- access html file?
EDITED:
I wrote a method to return the only one sub-folder as follow:
+ (NSString*) get1stSubFolder:(NSString*)folder
{
NSDirectoryEnumerator *directoryEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:folder];
//- no recursive
[directoryEnumerator skipDescendents];
NSString* file;
while (file = [directoryEnumerator nextObject])
{
BOOL isDirectory = NO;
BOOL subFileExists = [[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory];
if (subFileExists && !isDirectory) {
return file;
}
}
return nil;
}
I always get nil as result. Do you know where was I wrong at?
Use NSDirectoryEnumerator. It should help you.
Use NSDirectoryEnumerator like this.
NSURL *documentsDirectoryURL = [NSURL URLWithString:NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] ];
///If the folder you want to browse for subfolders is NSDocumentDirectory.
NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey];
NSDirectoryEnumerator *enumerator = [[[NSFileManager alloc] init]
enumeratorAtURL:documentsDirectoryURL
includingPropertiesForKeys:keys
options:0
errorHandler:^(NSURL *url, NSError *error) {
return YES;
}];
for (NSURL *url in enumerator) {
NSError *error;
NSNumber *isDirectory = nil;
if (! [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) {
NSLog(#"Error %#",error);
}
else if ([isDirectory boolValue]) {
NSLog(#"Folder URL: %#",url);
}else{
NSLog(#"File URL: %#",url);
}
}

objective-c cannot read from property list

self.toDoItems = [[NSMutableArray alloc] init]; //initialize array
self.dataFileName = #"PropertyList";
self.filePath = [self.dataFileName stringByAppendingString:#".plist"];
self.rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) objectAtIndex:0];
self.filePath = [self.rootPath stringByAppendingPathComponent:self.filePath];
self.NSSRootNodeName = #"ToDoList"; //name of the root node in the property list
// if (![[NSFileManager defaultManager] fileExistsAtPath: self.filePath]) {
// self.filePath = [[NSBundle mainBundle] pathForResource:self.dataFileName ofType:#"plist"];
// }
NSLog(#"File path: %#", self.filePath);
// Uncomment the following line to preserve selection between presentations.
self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
//read xml file and load to array
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:self.filePath];
if (plistXML==nil) {
NSLog(#"Error reading plistXML");
}
NSDictionary *rootDictionary = (NSDictionary *)[NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc];
if (!rootDictionary) {
NSLog(#"Error reading plist: %#, format: %d", errorDesc, format);
}
the output is below. I am not sure why I get these errors below:
My PropertyList.plist is sitting in my Documents folder inside my application.
could someone point out what I am doing wrong.
File path: /Users/Computer/Library/Application Support/iPhone Simulator/7.1/Applications/78B5F9BA-8376-4001-ACA0-936D9B4D6342/Documents/PropertyList.plist
Error reading plistXML
Error reading plist: stream had too few bytes, format: 0
FWIW, here is what worked for me:
NSFileManager *fileManager = [[NSFileManager alloc] init];
if ([fileManager fileExistsAtPath: [self filePathForState]])
{
printf("found state file\n");
NSData *data = [NSData dataWithContentsOfFile:[self filePathForState]];
...
}
else
{
printf("no state file found\n");
}
[fileManager release];
- (NSString *) filePathForState
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *result = [documentsDirectory stringByAppendingPathComponent: #"circles06"];
printf("filePathForState: %s\n", [result UTF8String]);
return result;
}
- (void) saveState
{
NSData *state = [model stateData];
[state writeToFile: [self filePathForState] atomically: NO];
}

App rejected due to downloading of image from server iOS

I have developed app in which i am downloading image from server and displaying in UITableView
App rejection reason
In particular, we found that on launch and/or content download, your app stores 2.67 MB. To check how much data your app is storing:
The iOS Data Storage Guidelines indicate that only content that the user creates using your app, e.g., documents, new files, edits, etc., should be backed up by iCloud.
Temporary files used by your app should only be stored in the /tmp directory; please remember to delete the files stored in this location when the user exits the app.
Data that can be recreated but must persist for proper functioning of your app - or because customers expect it to be available for offline use - should be marked with the "do not back up" attribute. For NSURL objects, add the NSURLIsExcludedFromBackupKey attribute to prevent the corresponding file from being backed up. For CFURLRef objects, use the corresponding kCFURLIsExcludedFromBackupKey attribute.
Here is my code shows how i am downloading data from server and displaying it:
- (BOOL)fileExist:(NSString *)name //Check's whether image Exists in Doc Dir.
{
BOOL theSuccess;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
NSFileManager *fileManager = [NSFileManager defaultManager];
theSuccess = [fileManager fileExistsAtPath:fullPath];
if(theSuccess){
return YES;
} else {
return NO;
}
}
- (void)downloadFile:(NSString *)urlFile withName:(NSString *)fileName //If image not exists it will download image.
{
NSString *trimmedString = [urlFile stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([trimmedString length]>0)
{
HTTPEaterResponse *response = [HTTPEater get:[NSString stringWithFormat:#"%#",trimmedString]];
if ([response isSuccessful])
{
[self saveImage:[[UIImage alloc] initWithData:[response body]] withName:fileName];
}
}
}
-(void)saveImage:(UIImage *)image withName:(NSString *)name //After downloading image it stores in Doc dir.
{
NSString *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:[#"Documents/" stringByAppendingString:name]];
[UIImagePNGRepresentation(image) writeToFile:pngPath atomically:YES];
}
- (UIImage *)loadImage:(NSString *)name //Used for displaying.
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
UIImage *img = [UIImage imageWithContentsOfFile:fullPath];
return img;
}
Code for displaying data:
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
...
if ([dicImages valueForKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:#"merchantimage"]])
{
cell.MerchntLogo.image=[dicImages valueForKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:#"merchantimage"]];
}
else
{
if (!isDragging_msg && !isDecliring_msg)
{
if ([[[msg_array objectAtIndex:indexPath.row] valueForKey:#"merchantimage"] length]!=0)
{
[dicImages setObject:[UIImage imageNamed:#"rowDefault.png"] forKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:#"merchantimage"]];
[self performSelectorInBackground:#selector(downloadImage_3:) withObject:indexPath];
}
}
else
{
cell.MerchntLogo.image=[UIImage imageNamed:#"rowDefault.png"];
}
}
...
}
-(void)downloadImage_3:(NSIndexPath *)path{
if ([[[msg_array objectAtIndex:path.row] valueForKey:#"merchantimage"] length]!=0)
{
NSString *str=[[msg_array objectAtIndex:path.row] valueForKey:#"merchantimage"];
UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:str]]];
[dicImages setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:#"merchantimage"]];
[tblProdDetail performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
}
Please help me figure out why my app has been rejected, and what I can do to rectify the problem.
Your app is clearly violating Apple's Data storage guidelines which states that only user-generated data should be stored in the Documents folder. This data is automatically backed up to iCloud and goes against the 5GB cap. If an app stores too much data in this folder (as deemed by Apple), then it can be rejected from the App Store.
Your data wont classify as user generated content and it exceeds 2 MB which is the limit.
You can prevent the data from being backed up by referring here.
https://developer.apple.com/library/ios/qa/qa1719/_index.html
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
BOOL result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result;
}
You need to do what they a talking about. Mark files
Just add in didFinishLaunching
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
[self applyAttributes:documentsDirectory];
And then implements this methods
#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
-(void)applyAttributes:(NSString *)folderPath
{
NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
NSString *fileName;
while (fileName = [filesEnumerator nextObject]) {
// NSLog(#"apply to %#", [[NSURL fileURLWithPath:[folderPath stringByAppendingPathComponent:fileName]] path]);
if([self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:[folderPath stringByAppendingPathComponent:fileName]]])
{
//NSLog(#"success applying");
}
//NSDictionary *fileDictionary = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:fileName] error:nil];
//fileSize += [fileDictionary fileSize];
}
}
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
if([[NSFileManager defaultManager] fileExistsAtPath: [URL path]])
{
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(#"Error excluding %# from backup %#", [URL lastPathComponent], error);
}
return success;
}
return NO;
}
Use this method to bypass storing data on iCloud
Pass file path to this method
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
BOOL result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result;
}

how to copy file from main bundle to Document Folder

I want to check one file in Document folder.I want if this file not exist in document folder copy it from main bundle to document folder. I write this code and this file to be copy but my problem here.....!!!! my file is .sqlite file (Database file) and when copy to document folder hasn't data in self!!!! why??? while the this file when is in main bundle has data in self.
this is my code but I don't know why not work!!!!
#define DataName #"mydatabase.sqlite"
- (void)viewDidLoad
{
[self CopyDatabase];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (NSString*)DatabasePath
{
NSArray *Paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *DocumentDir = [Paths objectAtIndex:0];
//NSLog(#"%#",DocumentDir);
return [DocumentDir stringByAppendingPathComponent:DataName];
}
- (void)CopyDatabase
{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:[self DatabasePath]];
NSString *FileDB = [[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:DataName];
if (success)
{
NSLog(#"File Exist");
return;
}
else
{
[fileManager copyItemAtPath:FileDB toPath:[self DatabasePath] error:nil];
}
}
I don't think your documents folder is updating because an older version of that db exists. You can purge your documents directory with the following method, and add it to the top of your viewDidLoad:
- (void)viewDidLoad
{
[self purgeDocumentsDirectory];
[self CopyDatabase];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)purgeDocumentsDirectory
{
NSLog(#"Purging Documents Directory...");
NSString *folderPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSError *error = nil;
for (NSString *file in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error:&error]) {
[[NSFileManager defaultManager] removeItemAtPath:[folderPath stringByAppendingPathComponent:file] error:&error];
}
}
This is my solution
-(void) copytoDocument {
NSString *openFile ;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pgnPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.text", #"100_Greatest_games"]];
if ([fileManager fileExistsAtPath:pgnPath] == NO)
{
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"100_Greatest_games" ofType:#"text"];
[fileManager copyItemAtPath:resourcePath toPath:pgnPath error:&error];
if (error) {
NSLog(#"Error on copying file: %#\nfrom path: %#\ntoPath: %#", error, resourcePath, pgnPath);
}
}
}

Resources