I got this app that needs to be updated with a new database.
I want to remove the old one and replace it with the new.
This is the code I'm using:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"Newdb.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"Newdb" ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSError *error;
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
return persistentStoreCoordinator;
}
I want my app to check at start-up if the Olddb.sqlite is there and if yes delete it!
here's the solution...
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [documentPaths objectAtIndex:0];
NSString *pathInDocuments = [docsDir stringByAppendingPathComponent:#"Olddb.sqlite"];
if (pathInDocuments) {
[fileManager removeItemAtPath:pathInDocuments error:NULL];
}
Related
I've been hunting for a solution for the last four hours and I am posting in desperation. My app was working perfectly on the simulator, my iPhone, and my ipad until I added an attribute to one of my Data Models.
My iPhone application uses Core Data and iCloud. In the AppDelegate, I create the managedObjectModel by merging two models. Everything seems fine until I try to save the ManagedObjectContext. That's when it crashes with:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This
NSPersistentStoreCoordinator has no persistent stores. It cannot
perform a save operation.'
This does not happen on the simulator.
I have tried:
Project->Clean Build Folder
Project->Clean
Deleting the app from my
device
Deleting the iCloud data from my iCloud back up
reboot computer
changed the ".momd" to ".mom" and back again (read about it in another question)
Thanks for the help.
EDIT to add code:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;
// TODO: Set up iCloud in another thread:
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *dataFileName = [NSString stringWithFormat:#"%#.sqlite", APP_TITLE_NO_SPACES];
NSString *iCloudDataDirectoryName = #"Data.nosync";
NSString *iCloudLogsDirectoryName = #"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
if (iCloud) {
NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if(fileSystemError != nil) {
NSLog(#"Error creating database directory %#", fileSystemError);
}
}
NSString *iCloudData = [[[iCloud path]
stringByAppendingPathComponent:iCloudDataDirectoryName]
stringByAppendingPathComponent:dataFileName];
NSLog(#"iCloudData = %#", iCloudData);
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
CLOUD_CONTAINER_IDENTIFIER, NSPersistentStoreUbiquitousContentNameKey,
iCloudLogsPath, NSPersistentStoreUbiquitousContentURLKey, nil];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[NSURL fileURLWithPath:iCloudData]
options:options
error:nil];
[psc unlock];
} else {
NSLog(#"iCloud is NOT working - using a local store");
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil];
[psc unlock];
}
__persistentStoreCoordinator = psc;
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ICLOUD_SOMETHING_CHANGED object:nil];
return __persistentStoreCoordinator;
}
Usually, it should okay after you deleted the program data. However, error indicates, that you do not have an inconsistency but simply no store at all. Assumption: you do not re-initiate it in case of a fault. Maybe, the following code can be useful:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"myApp.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Error, erase data
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
NSLog(#"store cleaned");
__persistentStoreCoordinator = nil;
return [self persistentStoreCoordinator];
}
return __persistentStoreCoordinator;
}
I want to copy my database from the NSBundle to the Document Directory.
This is the code to copy a file:
- (NSString *) getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingString:#"Mydata.sqlite"];
}
- (void) copyDatabaseIfNeeded
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success) {
NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Mydata.sqlite"];
success = [fileManager copyItemAtPath:defaultPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable file with message '%#'.", [error localizedDescription]);
}
}
But why is it that when i run this application on my iPad, it crashes?
check this line
NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Photo.png"];
I think This is wrong path
If you are using Core Data my advice is to manage the DB "move" at startup.
Just use the Core Data Stack management (you will get it for free from a built-in teplate).
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:#"MyData.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"MyData" ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
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_;
}
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
I always use that code when I've to manage data.
I have UIFileSharingEnabled set in my iPhone app. I wanted to do this so the user could have access to the database.sqlite file managed by Core Data. This way, they could drag and drop it between their multiple iPhones/touchs/iPads and use it as sort of an poor-man's sync.
However, I don't want them opening the sqlite file and a) mucking around the database and b) reverse engineering my data model.
Does anyone know a way to password protect or lock out the database so that the user can't open it outside the app?
You can filter out the files that you make visible to the app, but not what is visible to iTunes FS.
When I added my iTunes File Sharing support to my app, I wrote code to silently move the DB file to a new directory that would not be visible to iTFS. The code below moves the sqlite DB file from the Documents directory to the Application Support directory which is not visible to iTFS.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
//
// Move th DB file to a different directory because of the file sharing
// feature.
//
NSString *oldDBFile = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"db.sqlite"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *newDBFile;
NSString *dbpath;
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSError *error;
NSURL *storeUrl;
BOOL dir;
dbpath = ([paths count] > 0 ? [paths objectAtIndex:0] : #"");
newDBFile = [dbpath stringByAppendingPathComponent:#"db.sqlite"];
if ([dbpath length] &&
[fileMgr fileExistsAtPath:dbpath
isDirectory:&dir] == NO) {
if ([fileMgr createDirectoryAtPath:dbpath
withIntermediateDirectories:YES
attributes:nil error:&error] == NO) {
NSLog(#"Cannot create %#: %# %#",
dbpath,
[error localizedDescription],
[error userInfo]);
}
}
if ([fileMgr fileExistsAtPath:oldDBFile]) {
if ([fileMgr moveItemAtPath:oldDBFile
toPath:newDBFile
error:&error] != YES) {
NSLog(#"Error moving DB: %#: %#", [error localizedDescription], [error userInfo]);
storeUrl = [NSURL fileURLWithPath:oldDBFile];
} else {
storeUrl = [NSURL fileURLWithPath:newDBFile];
}
} else {
storeUrl = [NSURL fileURLWithPath:newDBFile];
}
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:
[self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeUrl
options:options
error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
// Handle the error.
}
return persistentStoreCoordinator;
}
Maybe you can use some ZIP or RAR library as they have support for password protection. Then zip the sqlite file when your app moves to background and unzip when comes to foreground.
I have imported sqlite prepopulated dbs to my coredata projects before, but now I have created a project in the 3.2.5. xcode, wich changes nsurl for nstring in the AppDelegate, so I went with that, But now my sqlite doesnt import to the project,
if I leave my PersistentStoreCoordinator to create the new db blank it works fine,
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"ChildCare_v02.sqlite"];
but when I change the code to import the prepopulated db (called the same just to clarify), it gives me a warning and crashes,
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"ChildCare_v02.sqlite"]; //WARNING !! here
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
//NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"ChildCare_v02.sqlite"]; //actual SDK style for blank db
// Put down default db if it doesn't already exist
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"ChildCare_v02" ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
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_;
}
THIS is the crash log in console
-[NSURL stringByAppendingPathComponent:]: unrecognized selector sent to instance 0x5b40e50
2011-02-15 21:06:59.245 Staff_02c[469:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURL stringByAppendingPathComponent:]: unrecognized selector sent to instance 0x5b40e50'
How to fix this please??
Just when I tough I was getting Core data !! dough!!
apple changed the helper method that returns the application dictionary in the core data templates.
You are relying on this version:
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
but apple changed it to this version
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
to fix it, just change this.
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"ChildCare_v02.sqlite"]; //WARNING !! here
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
//NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"ChildCare_v02.sqlite"]; //actual SDK style for blank db
to this
//NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"ChildCare_v02.sqlite"]; //WARNING !! here
//NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSURL *storeUrl = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"ChildCare_v02.sqlite"]; //actual SDK style for blank db
sorry, but omfg
thanks Ishu, you helped me a lot by pointing the NSArray way!!!
this was the solution I ended up by enlightenment !
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"ChildCare_v02.sqlite"];
NSString *storePath = [[NSBundle mainBundle] pathForResource:#"ChildCare_v02" ofType:#"sqlite"];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"ChildCare_v02.sqlite"]; //este es el que sirve!!! CREE ESTE
NSLog(#"store URL %#", storeURL);
// Put down default db if it doesn't already exist
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:writableDBPath]) {
NSLog(#"proceda aqui");
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"ChildCare_v02" ofType:#"sqlite"];
NSLog(#"no existe todavia");
NSLog(#"defalultStorePath %#", defaultStorePath);
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:writableDBPath error:NULL];
NSLog(#"storePath= %#", storePath);
}
}
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_;
}
hope it helps some noob like me wanting to import prepopulated sqlite to a coredata db,
note that first need to create blank db, to keep the structure and then populated (I used SQLite database browser to import CSV columns to my sqlite)
ss9
You don't need to use NSString paths at all, it can all be done with NSURL methods.
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Database.sqlite"];
// If the database doesn't exist copy in the default one
if (![storeURL checkResourceIsReachableAndReturnError:NULL])
{
NSURL *defaultStoreURL = [[NSBundle mainBundle] URLForResource:#"Database" withExtension:#"sqlite"];
if ([defaultStoreURL checkResourceIsReachableAndReturnError:NULL])
{
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager copyItemAtURL:defaultStoreURL toURL:storeURL error:NULL];
}
}
stringByAppendingPathComponent this method is instance method of NSString class.so you cant access this method on NSURL.
so for correction change this line
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"ChildCare_v02.sqlite"];
by this code
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"ChildCare_v02.sqlite"];
The crash isn't related specifically to Core Data.
Looks like you're calling a method that doesn't exist.
In NSURL the method is "URLByAppendingPathComponent".
If you want stringByAppendingPathComponent, that's in NSString.
You most likely had a warning for this during build.
I have created a folder within the Documents folder in my application directory .
I wanted to rename that folder through code,but not able to understand how to do it.
Please help me out.
Have you tried?
NString *newDirectoryName = #"<new folder name>";
NSString *oldPath = #"<path to the old folder>";
NSString *newPath = [[oldPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newDirectoryName];
NSError *error = nil;
[[NSFileManager defaultManager] moveItemAtPath:oldPath toPath:newPath error:&error];
if (error) {
NSLog(#"%#",error.localizedDescription);
// handle error
}
NSString *oldDirectoryPath = #"Type your old directory Path";
NSArray *tempArrayForContentsOfDirectory =[[NSFileManager defaultManager] contentsOfDirectoryAtPath:oldDirectoryPath error:nil];
NSString *newDirectoryPath = [[oldDirectoryPath stringByDeletingLastPathComponent]stringByAppendingPathComponent:newDirectoryname];
[[NSFileManager defaultManager] createDirectoryAtPath:newDirectoryPath attributes:nil];
for (int i = 0; i < [tempArrayForContentsOfDirectory count]; i++)
{
NSString *newFilePath = [newDirectoryPath stringByAppendingPathComponent:[tempArrayForContentsOfDirectory objectAtIndex:i]];
NSString *oldFilePath = [oldDirectoryPath stringByAppendingPathComponent:[tempArrayForContentsOfDirectory objectAtIndex:i]];
NSError *error = nil;
[[NSFileManager defaultManager] moveItemAtPath:oldFilePath toPath:newFilePath error:&error];
if (error) {
// handle error
}
}
Using moveItemAtPath should work. Sometimes the directory isn't actually "renamed" but really moved to another place. In which case the target path directory structure needs to be created as well.
Here a code snippet i'm using that works well :
-(BOOL)renameDir:(NSString *)dirPath asDir:(NSString *)newDirPath cleanExisting:(BOOL)clean
{
NSError *error = nil;
NSFileManager *fm = [NSFileManager defaultManager];
if (clean && [fm fileExistsAtPath:newDirPath])
{
[fm removeItemAtPath:newDirPath error:&error];
if (error != nil)
{
NSLog(#"Error while renameDir %# as %# :\n%#",dirPath,newDirPath,error);
return NO;
}
}
//Make sure container directories exist
NSString *newDirContainer = [newDirPath stringByDeletingLastPathComponent];
if (![fm fileExistsAtPath:newDirContainer])
{
[fm createDirectoryAtPath:newDirContainer withIntermediateDirectories:YES attributes:nil error:&error];
}
if (error==nil)
{
[fm moveItemAtPath:dirPath toPath:newDirPath error:&error];
}
if (error!=nil)
{
NSLog(#"error while moveItemAtPath : %#",error);
}
return (error==nil);
}
This always work
NSLog (#"Copying download file from %# to %#", aPath, bPath);
if ([[NSFileManager defaultManager] fileExistsAtPath: bPath]) {
[[NSFileManager defaultManager] removeItemAtPath: bPath
error: &error];
}
if (![[NSFileManager defaultManager] copyItemAtPath: aPath
toPath: bPath
error: &error]){}
if ([[NSFileManager defaultManager] removeItemAtPath: aPath
error: &error]) {}
This is good article for renaming, deleting and create files.
// For error information
NSError *error;
// Create file manager
NSFileManager *fileMgr = [NSFileManager defaultManager];
// Point to Document directory
NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
// Rename the file, by moving the file
NSString *filePath2 = [documentsDirectory stringByAppendingPathComponent:#"file2.txt"];
// Attempt the move
if ([fileMgr moveItemAtPath:filePath toPath:filePath2 error:&error] != YES)
NSLog(#"Unable to move file: %#", [error localizedDescription]);
// Show contents of Documents directory
NSLog(#"Documents directory: %#",
[fileMgr contentsOfDirectoryAtPath:documentsDirectory error:&error]);
http://iosdevelopertips.com/data-file-management/iphone-file-system-creating-renaming-and-deleting-files.html