Renaming an existing file with Obj-C - objective-c

I've seen this question asked a few times but I have been unable thus far to achieve success using any of the post solutions. What I am trying to do is rename a file in the local storage of an app (also kind of new to Obj-c). I am able to retrieve the old path and create the new path, but what would I have to write in order to actually change the files name?
What I have thus far is:
- (void) setPDFName:(NSString*)name{
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString* initPath = [NSString stringWithFormat:#"%#/%#",[dirPaths objectAtIndex:0], #"newPDF.pdf"];
NSString *newPath = [[NSString stringWithFormat:#"%#/%#",
[initPath stringByDeletingLastPathComponent], name]
stringByAppendingPathExtension:[initPath pathExtension]];
}

NSError *error = nil;
[[NSFileManager defaultManager] moveItemAtPath:initPath toPath:newPath error:&error];

The code is very messy; try this:
- (BOOL)renameFileFrom:(NSString*)oldName to:(NSString *)newName
{
NSString *documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) objectAtIndex:0];
NSString *oldPath = [documentDir stringByAppendingPathComponent:oldName];
NSString *newPath = [documentDir stringByAppendingPathComponent:newName];
NSFileManager *fileMan = [NSFileManager defaultManager];
NSError *error = nil;
if (![fileMan moveItemAtPath:oldPath toPath:newPath error:&error])
{
NSLog(#"Failed to move '%#' to '%#': %#", oldPath, newPath, [error localizedDescription]);
return NO;
}
return YES;
}
and call this using:
if (![self renameFileFrom:#"oldName.pdf" to:#"newName.pdf])
{
// Something went wrong
}
Better still, put the renameFileFrom:to: method into a utility class and make it a class method so it can be called from anywhere in your project.

Related

Objective C strange if (NO) condition

I have facing a strange issue in Objective C. Please look at the code below.
+(BOOL)isWritableCopyofAppConfig{
BOOL response = false;
NSURL *urlConfig = [NSURL URLWithString:APP_CONFIG_PATH];
NSData *dataReturn = [NSData dataWithContentsOfURL:urlConfig];
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0]stringByAppendingPathComponent:#"AppConfig.plist"];
if (dataReturn != nil ){
// It always goes here
}
else{
// Never reach here.
}
return response;
}
Even if I change the above if condition to the following:
if (NO){
// It always goes here even if there is NO.
}
else{
// Never reach here.
}
I tried cleaning the project i tried other things like directly comparing NO == YES still it goes inside the first block.
Does anyone knows how to solve this or what is this behavior?
EDIT: The entire code
+(BOOL)isWritableCopyofAppConfig{
BOOL response = false;
NSURL *urlConfig = [NSURL URLWithString:APP_CONFIG_PATH];
NSData *dataReturn = [NSData dataWithContentsOfURL:urlConfig];
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0]stringByAppendingPathComponent:#"AppConfig.plist"];
if (NO){
if (filePath != nil){
response = [dataReturn writeToFile:filePath atomically:YES];
}
}
else{
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"AppConfig" ofType:#".plist"];
[fileMgr copyItemAtPath:resourcePath toPath:filePath error:nil];
}
return response;
}
Its a class method (called from AppDelegate.m):
AppConfigHandler.isWritableCopyofAppConfig();
EDIT: Screenshot of debugger

Using apples suggested code isnt excluding files from icloud backup

I have an app that has been rejected 3 times due to icloud backup issues. Apple have written back to say that I need to use there bit of code to exclude the files from being backed up. However this isnt working and i am at wits end.
Here is the code i've used
- (BOOL)downloadFile:(NSString *)fileURI targetFolder:(NSString *)targetFolder targetFilename:(NSString *) targetFilename{
#try{
NSError *error = nil;
NSURL *url = [NSURL URLWithString:fileURI];
if(![url setResourceValue:#"YES" forKey:NSURLIsExcludedFromBackupKey error:&error]){
NSLog(#"KCDM: Error excluding %# from backup %#", fileURI, error);
}else{
NSData *urlData = [NSData dataWithContentsOfURL:url];
if ( urlData )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingString:targetFolder];
NSError *error = nil;
if(![[NSFileManager defaultManager] fileExistsAtPath:dataPath]){
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:&error];
}
NSString *filePath = [NSString stringWithFormat:#"%#/%#%#", documentsDirectory,targetFolder,targetFilename];
return [urlData writeToFile:filePath atomically:YES];
}
}
}
#catch(NSException * e){
NSLog(#"Error download: %#",e);
}
return false;
}
what am i doing wrong?
You try to set NSURLIsExcludedFromBackupKey for the http://-Url you download from the web. That won't work.
You have to set this key-value pair for the actual file that is saved on the device.
Additionally you are not supposed to set this value to the string #"YES", you must use a NSNumber object representing the boolean value YES.
For example:
NSString *filePath = [NSString stringWithFormat:#"%#/%#%#", documentsDirectory,targetFolder,targetFilename];
if ([urlData writeToFile:filePath atomically:YES]) {
// did write correctly
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
if(![fileURL setResourceValue:#YES forKey:NSURLIsExcludedFromBackupKey error:&error]){
NSLog(#"KCDM: Error excluding %# from backup %#", fileURI, error);
return NO;
}
// could set NSURLIsExcludedFromBackupKey
return YES;
}
// could not write to file
return NO;

NSApplicationSupportDirectory invalid CFStringRef

I'm trying to store a file in the NSApplicationSupportDirectory, since i have a preloaded folder in my app, which i want to add files to once the app have been initialized. I'm trying to NSLog the content of the file, so i can see if it actually worked. From the debugger, i can see that the content is , which i don't not what means. Anybody?
NSString *document = [NSString stringWithFormat:#"%# %# %# %# %#", description, focus, level, equipment, waterDepth];
//NSLog(#"%#", document);
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *supportDirectory = [paths objectAtIndex:0];
//filename
NSString *filename = [NSString stringWithFormat:#"%#/%#", supportDirectory,[_nameTextField.text stringByAppendingString:#".txt"]];
NSLog(#"%#", supportDirectory);
NSLog(#"%#", filename);
[document writeToFile:filename atomically:NO encoding:NSStringEncodingConversionAllowLossy error:nil];
NSString *content = [[NSString alloc]initWithContentsOfFile:filename usedEncoding:nil error:nil];
NSLog(#"%#", content);
You're not passing a string encoding, you are passing NSStringEncodingConversionAllowLossy which is an option that can affect how encoding conversion happens for certain methods (not the one you're using). You need to pass something like NSUTF8StringEncoding.
When you write or read files, it is highly recommended to use the error parameter and handle the cases where you get an error. Also, this is very useful to help you debug your code.
For example, in your case, you can do like this:
NSError *error = nil;
BOOL success = [document writeToFile:filename atomically:NO encoding:NSStringEncodingConversionAllowLossy error:&error];
if (!success) {
NSLog(#"Could not write file: %#", error);
} else {
NSString *content = [[NSString alloc]initWithContentsOfFile:filename usedEncoding:nil error:&error];
if (!content) {
NSLog(#"Could not read file: %#", error);
}
}
If you get an error that says that The operation couldn’t be completed. No such file or directory, that means that you did not previously create the folder. So you create it before trying to add content to it:
NSString *supportDirectory = [paths objectAtIndex:0];
NSError *error = nil;
BOOL success;
if (![[NSFileManager defaultManager] fileExistsAtPath: supportDirectory]) {
success = [[NSFileManager defaultManager] createDirectoryAtPath:supportDirectory withIntermediateDirectories:YES attributes:nil error:&error];
if (!success) {
NSLog(#"Could not create directory: %#", error);
}
}

Getting the contents of a file in Xcode

In my project I have a plain text file called GAME.js, and I'm trying to get the contents of the file.
[NSString stringWithContentsOfFile:#"GAME.js" encoding:NSUTF8StringEncoding error:nil];
sounds like it should work, but it's just returning an empty string.
Please help me fix this.
Put GAME.js into the Resources folder in your Xcode project and use the following code to get the contents of the file.
NSError *error = nil;
NSString* path = [[NSBundle mainBundle] pathForResource:#"GAME" ofType:#"js"];
NSString* gameFileContents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
If you pass in a NSError it will tell you exactly what the problem is:
NSError *error = nil;
NSString *myString = [NSString stringWithContentsOfFile:#"GAME.js" encoding:NSUTF8StringEncoding error:&error];
if (error) {
NSLog(#"%#", [error localizedDescription]);
} else {
NSLog(#"%#", myString);
}
NSError Documentation
Also, check to see if it is in your documents directory which can be accessed with NSSearchPathForDirectoriesInDomains:
NSError *error = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *fullPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"GAME.js"];
NSString *myString = [NSString stringWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:&error];
if (error) {
NSLog(#"%# - %#", [error localizedDescription], [error localizedFailureReason]);
} else {
NSLog(#"%#", myString);
}

SQLite Table does not exist

EDIT: SOLVED! answer below first code box
When i try to connect with a sqlite database (with a table TblTest). In debug mode in my app, the error is:
* Assertion failure in -[QueryClass getTestData:],
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cant build SQL to read item [no such table: TblTest]'
In release mode (simulator), it does not give an error but it will not read the database.
The code behaves like it can connect to the db, but can NOT read the TblTest?
I already reset the simulator and used clean and build.
Sorry for the long code:
#implementation QueryClass
#synthesize databaseName;
#synthesize databaseLite;
-(id)initWithDatabase:(NSString *)databaseNameP{
if(self = [super init]){
[self createEditableCopyOfDatabaseIfNeeded];
self.databaseName = databaseNameP;
self.databaseLite = [self getNewDBConnection];
}
return self;
}
- (void)createEditableCopyOfDatabaseIfNeeded {
NSLog(#"Creating editable copy of database");
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:self.databaseName];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseName];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message ‘%#’.", [error localizedDescription]);
}
}
- (sqlite3 *) getNewDBConnection{
sqlite3 *newDBconnection;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:self.databaseName];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &newDBconnection) == SQLITE_OK) {
NSLog(#"Database Successfully Opened ");
} else {
NSLog(#"Error in opening database ");
}
return newDBconnection;
}
-(NSMutableArray *)getTestData:(NSInteger) testId{
(NSMutableArray *testArray = [[NSMutableArray alloc]init];
int ret;
sqlite3_stmt *selStmt = nil;
const char *sql = "SELECT testId, name, FROM TblTest WHERE testId = ?";
if (!selStmt)
{ // build update statement
if (sqlite3_prepare_v2(self.databaseLite, sql, -1, &selStmt, NULL)!=SQLITE_OK)
{
selStmt = nil;
}
}
sqlite3_bind_int(selStmt, 1, testId);
if(!selStmt){
NSAssert1(0, #"Cant build SQL to read item [%s]", sqlite3_errmsg(self.databaseLite));
}
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{ // get the fields from the record set and assign to item
Test *test = [[Test alloc]init];
NSNumber *testId = [NSNumber numberWithInt: (int) sqlite3_column_int(selStmt, 0)];
NSString *name = [NSString stringWithUTF8String:(char *) sqlite3_column_text(selStmt, 1)];
test.testId =testId;
test.name =name;
[testArray addObject:pill];
[test release];
}
sqlite3_reset(selStmt);
return [testArray autorelease];
}
//in my function i do:
qc = [[QueryClass alloc]initWithDatabase:#"databaseLite.sql"];
[qc getTestData:0];
I rewrote my code using this tutorial and it works like a charm. :)
Thanks
-(id)initWithDatabase:(NSString *)databaseNameP{
if(self = [super init]){
[self createEditableCopyOfDatabaseIfNeeded];
[self initializeDatabase];
}
return self;
}
// Creates a writable copy of the bundled default database in the application Documents directory.
- (void)createEditableCopyOfDatabaseIfNeeded {
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"databaseLite4.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"databaseLite4.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
// Open the database connection and retrieve minimal information for all objects.
- (void)initializeDatabase {
// The database is stored in the application bundle.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.path = [documentsDirectory stringByAppendingPathComponent:#"databaseLite4.sqlite"];
}
When you solve your own problems, you should provide your solution as an answer rather than updating your question. It is possible (and recommended in this situation) to answer your own question and accept it as your answer. You will not gain any reputation for accepting your own answer, but the question will be correctly listed as solved.
Below is the answer I extracted from your question. Feel free to accept it.
I rewrote my code using this tutorial and it works like a charm. :)
Here's my solution:
-(id)initWithDatabase:(NSString *)databaseNameP{
if(self = [super init]){
[self createEditableCopyOfDatabaseIfNeeded];
[self initializeDatabase];
}
return self;
}
// Creates a writable copy of the bundled default database in the application Documents directory.
- (void)createEditableCopyOfDatabaseIfNeeded {
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"databaseLite4.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"databaseLite4.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
// Open the database connection and retrieve minimal information for all objects.
- (void)initializeDatabase {
// The database is stored in the application bundle.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.path = [documentsDirectory stringByAppendingPathComponent:#"databaseLite4.sqlite"];
}