[NSFileManager copyItemAtPath:toPath:error:]: source path is nil - objective-c

I am trying to add a sqlite DB into an application using this: CoreData: Preload Data in Your iOS App
Following the tutorial i hit a problem:
[NSFileManager copyItemAtPath:toPath:error:]: source path is nil
I use the following code:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Peter_R0_1.sqlite"];
if(![[NSFileManager defaultManager] fileExistsAtPath:[storeURL path]]) {
NSString *sqlitePath = [[NSBundle mainBundle] pathForResource:#"Peter_R0_1" ofType:#"sqlite" inDirectory:nil];
NSError *anyError = nil;
BOOL success = [[NSFileManager defaultManager] copyItemAtPath:sqlitePath toPath:[storeURL path] error:&anyError];
}
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
I would very much appreciate some help on this problem

Well, that error means the NSString *sqlitePath is == nil so 99% chance it's one or more of the following:
The file is not added to the correct Target in the project
Verify via "Target Membership" under the File Inspector view for the Peter_R0_1.sqlite file)
And/Or: You're copying the file to a specific sub-directory instead of the default.
Verify the file is listed under "Copy Bundle Resources" under your Target's "Build Phases" and NOT under "Copy Files" with a custom destination or sub-path.
And/Or: You've got a typo in the file name.

Related

NSFileHandle from NSURL failure

I'm trying to write some data to a file. I am able to obtain an NSURL from a file dialog and the NSURL obtained has the following value
file:///Users/brad/Documents/2016-05-04-06-53-35.csv
My code does the following:
NSURL* myFile = [panel URL]; // is file:///Users/brad/Documents/2016-05-04-06-53-35.csv
NSError *error = nil;
NSFileHandle *myFileHandle = [NSFileHandle fileHandleForWritingToURL:myFile error:&error];
NSLog(#"%#",error);
if (myFileHandle)
{
... // do something
}
else
{
NSLog(#"File operation failed");
}
I get an error which indicates the following
Error Domain=NSCocoaErrorDomain Code=2 "(null)" UserInfo={NSFilePath=/Users/brad/Documents/
Also myFileHandle is nil.
Any clues ?
See the documentation for NSFileHandle fileHandleForWritingToURL:error:. You get back nil if the file doesn't already exist.
Use NSFileManager to first check if the file exists or not. If not, use NSFileManager createFileAtPath:contents:attributes: to create an empty file.
NSURL *myFile = [panel URL];
if (![[NSFileManager defaultManager] fileExistsAtPath:[myFile path]]) {
[[NSFileManager defaultManager] createFileAtPath:[myFile path] contents:[NSData data] attributes:nil];
}
NSError *error = nil;
NSFileHandle *myFileHandle = [NSFileHandle fileHandleForWritingToURL:myFile error:&error];

How to replace a file or folder by using NSFileManager?

For using "copyItemAtPath" method of NSFileManager, if exists the same file or folder, occur error.
Is there the replace feature in NSFileManager?
(If exists the same file, delete and copy If not, just copy.)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self generateTableContents];
}
- (void)generateTableContents {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *appsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [appsDirectory objectAtIndex:0];
[fileManager changeCurrentDirectoryPath:documentPath];
[fileManager createDirectoryAtPath:#"user_List1" withIntermediateDirectories:YES attributes:nil error:nil];
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
NSError *error; // to hold the error details if things go wrong
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"IMG_0523" ofType:#"JPG"];
if ([fileManager copyItemAtPath:sourcePath toPath: #"./user_List1/newIMG_0523.JPG" error:&error]) {
NSLog(#"Copy complete!");
} else {
NSLog(#"Copy Failed : %#", error);
}
if ([fileManager copyItemAtPath:#"./user_List1" toPath: #"./user_List2" error:&error]) {
NSLog(#"Copy complete!");
} else {
NSLog(#"Copy Failed : %#", error);
}
}
Excuted result is complete.
/Users/nice7285/Library/Caches/appCode10/DerivedData/tempPrg-dd15264d/Build/Products/Debug-iphonesimulator/tempPrg.app/tempPrg
Simulator session started with process 1184
2012-10-04 06:28:32.653 tempPrg[1184:11303] Copy complete!
2012-10-04 06:28:32.672 tempPrg[1184:11303] Copy complete!
Process finished with exit code 143
But When already exist folder.
Result is fail.
2012-10-04 06:48:31.488 tempPrg[1243:11303] Copy Failed
2012-10-04 06:48:31.497 tempPrg[1243:11303] Copy Failed
You need to do an atomic save, for example:
NSData *myData = ...; //fetched from somewhere
[myData writeToFile:targetPath atomically:YES];
But since you're using copyItemAtPath, I have no idea if atomically works with it so I would just go for the quick dirty hack:
if ([fileManager fileExistsAtPath:txtPath] == YES) {
[fileManager removeItemAtPath:txtPath error:&error]
}
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"txtFile" ofType:#"txt"];
[fileManager copyItemAtPath:resourcePath toPath:txtPath error:&error];
Sources: IOS: copy a file in documents folder
Starting with iOS 4 (and macOS 10.7) there is an explicit method for replacing one item with another. It even keeps the properties of the original file (optional)
- (BOOL)replaceItemAtURL:(NSURL *)originalItemURL withItemAtURL:(NSURL *)newItemURL backupItemName:(NSString *)backupItemName options:(NSFileManagerItemReplacementOptions)options resultingItemURL:(NSURL * _Nullable *)resultingURL error:(NSError * _Nullable *)error;
Replaces the contents of the item at the specified URL in a manner
that ensures no data loss occurs.
replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:

Still backups to iCloud even when addSkipBackupAttributeToItemAtURL is implemented?

My recent iOS app just got rejected because the application is storing data on Documents so it is backed up by iCloud, this is not allowed since the data is downloaded from a server.
I'm trying to rebuild the code right now and have hit a tough spot when storing the data in the a folder calles Application Support instead.
But even though I'm using addSkipBackupAttributeToItemAtURL it still shows up as a backup to iCloud.
I'm only targeting 5.1 so it's not a versioning problem.
I've added the affected code here below:
NSString *newPath = [NSMutableString stringWithFormat:#"%#/Library/Application Support/", NSHomeDirectory()];
if (![[NSFileManager defaultManager] fileExistsAtPath:newPath]) //Does directory already exist?
{
if (![[NSFileManager defaultManager] createDirectoryAtPath:newPath
withIntermediateDirectories:NO
attributes:nil
error:&error])
{
NSLog(#"Create directory error: %#", error);
}
}
NSString *guidesPath = [newPath stringByAppendingPathComponent:#"/Guides"];
if (![[NSFileManager defaultManager] fileExistsAtPath:guidesPath]) //Does directory already exist?
{
if (![[NSFileManager defaultManager] createDirectoryAtPath:guidesPath
withIntermediateDirectories:NO
attributes:nil
error:&error])
{
NSLog(#"Create directory error: %#", error);
}
}
NSString *dataPath = [guidesPath stringByAppendingPathComponent:dbName];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
{
if (![[NSFileManager defaultManager] createDirectoryAtPath:dataPath
withIntermediateDirectories:NO
attributes:nil
error:&error])
{
NSLog(#"Create directory error: %#", error);
}
}
NSString *newGuidesPath = [dataPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *guidesURL = [NSURL URLWithString:newGuidesPath];
[self addSkipBackupAttributeToItemAtURL:guidesURL];
NSString* path = [dataPath stringByAppendingPathComponent:
[NSString stringWithString: finalName] ];
if (![fileManager fileExistsAtPath:path]) {
[myData writeToFile:path atomically:YES];
NSString *docFile = [dataPath stringByAppendingPathComponent: #"guideid.txt"];
[[guideID dataUsingEncoding:NSUTF8StringEncoding] writeToFile:docFile atomically:NO];
DLog(#"Saved database here:%#", path);
}else{
DLog(#"Already exists, no need to copy");
}
}
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
assert([[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;
}
Actually found a solution,
I've encoded the URL which was not needed.
Just added this to the folder
NSURL *guidesURL = [NSURL fileURLWithPath:guidesPath];
[guidesURL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:NULL];
And skipped the exclude method, just flagged it inside the code, which seems to work.
Did you try create new back up on your device from icloud settings?

Prepopulate Core Data in iOS 5

There seem to be some modifications to the NSPersistentStoreCoordinator method is iOS 5.
I am trying to get a prepopulated database ... it doesn't seem to work, no crash but none of the data seems to exist... Any suggestions?
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storePath = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"DataModel.sqlite"];
/*
Set up the store.
For the sake of illustration, provide a pre-populated default store.
*/
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:[storePath absoluteString]]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"DataModel" ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:[storePath absoluteString] error:NULL];
}
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"DataModel.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
The problem is in the applicationDocumentsDirectory method that gives wrong absolute string. It is not really wrong, but is not suited for NSFileManager class.
The solution is simple. You need to write another method which I called applicationDocumentsDirectory2.
So first, go to header file of your AppDelegate and declare method:
- (NSString *)applicationDocumentsDirectory2;
Now, go to the .m file, and define a method:
- (NSString *)applicationDocumentsDirectory2 {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
And finally, just change persistentStoreCoordinator method into:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSError *error = nil;
NSString *storePath = [[self applicationDocumentsDirectory2] stringByAppendingPathComponent: #"DataModel.sqlite"];
/*
Set up the store.
For the sake of illustration, provide a pre-populated default store.
*/
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"DataModel" ofType:#"sqlite"];
if (defaultStorePath) {
if(![fileManager copyItemAtPath:defaultStorePath toPath:storePath error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"DataModel.sqlite"];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
That's it! :)

Error trying to access iOS store

All,
I have the following code in my project:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSError *error = nil;
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:#"My_Model.sqlite"];
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
- (NSString *)applicationDocumentsDirectory
{
NSError *err = nil;
return [NSString stringWithContentsOfURL:[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] encoding:NSUTF8StringEncoding error:&err];
}
And I am receiving an error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSURL initFileURLWithPath:]: nil string parameter'
What I don't understand is why this is returning s nil? I have referenced a book for this code and it seems to think it should work all ok. Any ideas?
Thanks in advance
Paul
Your -applicationDocumentsDirectory method looks very strange to me. Instead of returning the path of the documents dir, you try to actually return the contents of this directory (which is probably not possible to read, hence it will return nil).
Try replacing the method with
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
}