Writing a csv from app, Cocoa error 513 - ios

I am creating an iPhone app that writes to a CSV file. It seems the most simple method of this would be to add to an NSMutableString from an array. The code I have should be working expect I keep getting Cocoa error 513
The code is:
NSArray *firstArray=[NSArray arrayWithObjects:#"A",#"b",nil];
NSMutableString *csv = [NSMutableString stringWithString:#"Strings"];
NSUInteger count = [firstArray count];
for (NSUInteger i=0; i<count; i++ ) {
[csv appendFormat:#"\n %#",
[firstArray objectAtIndex:i]
];
}
NSString *yourFileName = #"leads.csv";
NSError *error;
BOOL res = [csv writeToFile:yourFileName atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (!res) {
NSLog(#"Error %# while writing to file %#", [error localizedDescription], yourFileName );
}
Thank you so much!

It is most likely because you are writing to a file location that you do not have permission to write.
Cocoa error 513 translates to the error NSFileWriteNoPermissionError.
Typically, this occurs when someone tries to write to a file within the applications bundle. You cannot modify the contents of a compiled app's bundle folder. This is because the bundle is a signed, compiled application.
When you eventually distribute the app through the iTunes App Store, the application has a digital signature that validates the contents of the app. This signature is generated at compile time and once signed, Apple does not want anyone tampering with the contents.
Make sure you are writing to an appropriate location, like Documents, Temp and Cache using something like the following:
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"subFolder"];
NSString *filePath = [dataPath stringByAppendingPathComponent:#"fileName.csv"];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
{
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error]; //Create folder
}
BOOL res = [csv writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (!res) {
NSLog(#"Error %# while writing to file %#", [error localizedDescription], yourFileName );
}
These folders are only accessible to your app. No other app can access the contents of these folders. (Likewise, your app cannot access another app's folders.)

Related

Empty documents directory after creating file with NSFileHandle

I'm writing an application for the Apple watch. I'm using the following method (from this SE answer) to write to a log file:
- (void) writeLogWith: (NSString *) content {
//Get the file path
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fileName = [documentsDirectory stringByAppendingPathComponent:#"whathappened.md"];
//create file if it doesn't exist
if(![[NSFileManager defaultManager] fileExistsAtPath:fileName])
[[NSFileManager defaultManager] createFileAtPath:fileName contents:nil attributes:nil];
//append text to file (you'll probably want to add a newline every write)
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:fileName];
[file seekToEndOfFile];
[file writeData:[content dataUsingEncoding:NSUTF8StringEncoding]];
[file closeFile];
return;
}
I'm running it by plugging in my phone and running it directly on my watch. The function is definitely executing (I've stepped thought with the debugger) and it also knows that the file exists and doesn't repeatedly try and create it.
Xcode tells me that the file information is:
Printing description of documentsDirectory:
/var/mobile/Containers/Data/PluginKitPlugin/8503AD6C-6EC9-4522-A867-27109B01B615/Documents
Printing description of documentsDirectory:
(NSString *) documentsDirectory = 0x16d66890
Printing description of fileName:
(NSString *) fileName = 0x16d66950
Printing description of fileName:
/var/mobile/Containers/Data/PluginKitPlugin/8503AD6C-6EC9-4522-A867-27109B01B615/Documents/whathappened.md
I'd like to know if it's writing things correctly, but when I look at the container (following these SE answers), the documents directory is empty.
My question is: where did my file go? And how can I find it?
I think what might be giving you problems is the NSFileHandle object. I have written thousands upon thousands of files to the documents folder and I have never used NSFileHandle to do this. Simply use the built in method on NSString to write your string to the file path.
Try this:
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [[documentsDirectory stringByAppendingPathComponent:#"whathappened"] stringByAppendingPathExtension:#"md"];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
}
NSString *string = #"The String You Want To Write.";
NSError *error;
[string writeToFile:filePath atomically:false encoding:NSUTF8StringEncoding error:&error];
if (error) {
NSLog(#"There was an error writing file\n%#", error.localizedDescription);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSLog(#"File exists :)");
}
else {
NSLog(#"File does not exist :(");
}
From other research, the answer appears to be:
If you are storing a file on the Apple Watch, it is stored in it's own container, which isn't visible via xcode.
It indeed, appears to be related to this bug report: https://openradar.appspot.com/radar?id=5021353337946112, found via this SE: How to export shared container of an iOS App with Xcode6.2?

how to use sqlite in iOS when i use iPhone to run the project

when i use simulator,i can find the database file in /documents .but when i use my iPhone to run the project,i can not find the database file.
what time should i create the database file or use this code in my project?
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolderPath = [searchPaths objectAtIndex:0];
NSString *dbFilePath = [documentFolderPath stringByAppendingString:DATABASENAME];
NSFileManager *fm = [NSFileManager defaultManager];
BOOL isExist = [fm fileExistsAtPath:dbFilePath];
if (!isExist) {
NSString *backupDbPath = [[[NSBundle mainBundle]resourcePath]stringByAppendingString:DATABASENAME];
[fm copyItemAtPath:backupDbPath toPath:dbFilePath error:nil];
}
For the first time or the database file does not exist in the documents directory, you have to copy DB file to document directory:
-(void)copyDatabaseIntoDocumentsDirectory{
// Check if the database file exists in the documents directory.
NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
// The database file does not exist in the documents directory, so copy it from the main bundle now.
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destinationPath error:&error];
// Check if any error occurred during copying and display it.
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}
}
Ref: http://www.appcoda.com/sqlite-database-ios-app-tutorial/
You can't access the directories of iPhone or iPad. So even if you successfully created a database, you won't see it. You can judge its existence by read data from it.

How to rename files/folders from document folder programmatically in iOS

I am working on functionality to save video files in document folder of application in iOS.
How to rename some files programmatically?
try this code :
NSError * err = NULL;
NSFileManager * fm = [[NSFileManager alloc] init];
BOOL result = [fm moveItemAtPath:#"/tmp/test.tt" toPath:#"/tmp/dstpath.tt" error:&err];
if(!result)
NSLog(#"Error: %#", err);
other wise use this method to rename file
- (void)renameFileWithName:(NSString *)srcName toName:(NSString *)dstName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePathSrc = [documentsDirectory stringByAppendingPathComponent:srcName];
NSString *filePathDst = [documentsDirectory stringByAppendingPathComponent:dstName];
NSFileManager *manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:filePathSrc]) {
NSError *error = nil;
[manager moveItemAtPath:filePathSrc toPath:filePathDst error:&error];
if (error) {
NSLog(#"There is an Error: %#", error);
}
} else {
NSLog(#"File %# doesn't exists", srcName);
}
}
There is no Direct API to rename the file . Though when you move the file from one place to another place, if that file in destination path not exists then iOS will create the file in the given name. For file you can just give the New name of your file, how it should be displayed/referenced.
you could check this answer. Good luck!

Move file from App bundle to Document folder on ios

I have file in my App bundle on iOS. How can I move it to be in Document folder?
Can this be done through some configuration or I need to make custom code for it?
By custom code I mean:
check is this first run of app:
if so, move files to the Document folder.
Please check out NSFileManager which allows you to copy files within the file system as required. You should be aware that Apple will reject your App if the copied file is not flagged to NOT backup to iCloud.
I use the following methods to copy a sqlite database from the bundle to a folder; it should work for your purpose with minor modification.
+ (void)copyBundleFileToStoresDirectory:(NSString *)filename
{
NSError *error;
NSURL *fileURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:filename ofType:nil]];
NSURL *pathURL = [SVOFileSystemMethods documentsSubdirectory:#"Stores" skipBackup:YES];
if (fileURL)
{
if([[NSFileManager defaultManager] copyItemAtURL:fileURL toURL:pathURL error:&error])
{
// NSLog(#"File successfully copied");
}
else
{
[[[UIAlertView alloc]initWithTitle:NSLocalizedString(#"error", nil) message: NSLocalizedString(#"Failed to copy database from bundle.", nil)
delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", nil) otherButtonTitles:nil] show];
NSLog(#"Error description-%# \n", [error localizedDescription]);
NSLog(#"Error reason-%#", [error localizedFailureReason]);
}
}
}
+ (NSURL *) documentsSubdirectory:(NSString *)subdirectoryName skipBackup:(BOOL) skipBackup
{
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:subdirectoryName]; //untested change here -- was literal #"/Stores"
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
{
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:&error]; //Create folder
NSURL *finalURL = [NSURL fileURLWithPath:dataPath];
if (skipBackup)
[SVOFileSystemMethods addSkipBackupAttributeToItemAtURL:finalURL]; // flag to exclude from backups.
return finalURL;
}
else
return [NSURL fileURLWithPath:dataPath]; // already existed
}
//
// flags URL to exclude from backup
//
+ (BOOL) addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
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;
}
From what I understand, you can't "move" files from the app bundle to the app directory, since that requires deleting them from the bundle. You'll get an access denied, assuming your code is set up right.
You can "copy" files however, since that it simply a read.
In my case, I had a whole bunch of files that I wanted to move to the app's Library directory but was unable. Additionally, the copy operation was far too costly because of the quantity of files.
In this case, I changed the app logic to check for "fresh" information first (that I would save to the Library folder), & if it wasn't there then fall back to the App bundle to look for an old/original copy of the file.

Copy images from an app to Documents Directory and rewrite them after it

I have an app where I have a certain amount of .jpg pictures (roughly 300). They serve as something to start with, because they're actually located in the internet, but obviously it's more convenient for user not to download all of them at the first start of the App, but to have them pre-packed.
I am required to rewrite these images everytime I get new information from server. Obviously, I can't touch the app bundle, so I see my steps like this:
Unpack the images from bundle to the Documents Directory at the first start of an App.
Access them only from Documents Directory, but not from bundle.
If it's necessary, I should rewrite them.
And thus my code will be unified, cause I will always use the same path to get the image.
The problem is that I know very little about the whole file system thing in iOS, so I don't know how to unpack the particular bundle contents to Documents Directory and also I don't know how to write to Documents Directory either.
Could you please help me with some code and also confirm that my solution scheme is right?
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *destPath = [documentsDirectory stringByAppendingPathComponent:#"images"]; //optionally create a subdirectory
//"source" is a physical folder in your app bundle. Once that has a blue color folder (not the yellow group folder)
// To create a physical folder in your app bundle: drag a folder from Mac's Finder to the Xcode project, when prompts
// for "Choose options for adding these files" make certain that "Create folder references for …" is selected.
// Store all your 300 or so images into this physical folder.
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"source"];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destPath error:&error];
if (error)
NSLog(#"copying error: %#", error);
Edited per additional comment from the OP:
To rewrite with the same file name to the same directory, you can use a combination of fileExistsAtPath and removeItemAtPath to detect and remove the existing file before writing.
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
}
// now proceed to write-rewrite
Try this code
-(void)demoImages
{
//-- Main bundle directory
NSString *mainBundle = [[NSBundle mainBundle] resourcePath];
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error = [[NSError alloc] init];
NSArray *mainBundleDirectory = [fm contentsOfDirectoryAtPath:mainBundle error:&error];
NSMutableArray *images = [[NSMutableArray alloc]init];
for (NSString *pngFiles in mainBundleDirectory)
{
if ([pngFiles hasSuffix:#".png"])
{
[images addObject:pngFiles];
}
}
NSLog(#"\n\n Doc images %#",images);
//-- Document directory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
//-- Copy files form main bundle to document directory
for (int i=0; i<[images count]; i++)
{
NSString *toPath = [NSString stringWithFormat:#"%#/%#",documentDirectory,[images objectAtIndex:i]];
[fileManager copyItemAtPath:[NSString stringWithFormat:#"%#/%#",mainBundle,[images objectAtIndex:i]] toPath:toPath error:NULL];
NSLog(#"\n Saved %#",fileManager);
}
}

Resources