I have my CoreDataManager Class and initialising Core Data Objects.
But when below piece of code runs it throws and error and cause crashing the app.
NSPersistentStoreCoordinator has no persistent stores (can't open)
When i debug the code it shows that the persistentStore object is actually nil.
Here is My CoreDataManager.m file
+ (id)sharedInstance {
static CoreDataManager *instance_ = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance_ = [[self alloc] init];
});
return instance_;
}
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [NSManagedObjectContext new];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [[NSManagedObjectModel alloc]initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"AppTutor" withExtension:#"momd"]];
return managedObjectModel;
}
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *documentsStorePath =
[[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent:#"AppTutor.sqlite"];
// if the expected store doesn't exist, copy the default store
if (![[NSFileManager defaultManager] fileExistsAtPath:documentsStorePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"AppTutor" ofType:#"sqlite"];
if (defaultStorePath) {
[[NSFileManager defaultManager] copyItemAtPath:defaultStorePath toPath:documentsStorePath error:NULL];
}
}
persistentStoreCoordinator =
[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// add the default store to our coordinator
NSError *error;
NSURL *defaultStoreURL = [NSURL fileURLWithPath:documentsStorePath];
NSPersistentStore *store = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:defaultStoreURL
options:nil
error:&error];
if (store == nil) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
// setup and add the user's store to our coordinator
NSURL *userStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"AppTutor.sqlite"];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:userStoreURL
options:nil
error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
return persistentStoreCoordinator;
}
Can you try to add these options to the addPersistentStoreWithType function?
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:userStoreURL
options:options
error:&error]
Related
I'm trying to add a sqlite persistent store in Library/Application-Support folder as shown below:
- (NSManagedObjectModel *)managedObjectModel
{
if (!_managedObjectModel)
{
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"delete" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
}
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (!_persistentStoreCoordinator)
{
#synchronized(self)
{
if (!_persistentStoreCoordinator)
{
NSError *error = nil;
NSURL *storeURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject] #"delete.sqlite"];
NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
NSPersistentStore * persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];
_persistentStoreCoordinator = persistentStoreCoordinator;
}
}
}
return _persistentStoreCoordinator;
}
This fails with the following error:
CoreData: error: -addPersistentStoreWithType:SQLite configuration:(null)
URL:file:///Users/harshithg/Library/Developer/CoreSimulator/Devices/D9A32558-558A-4E0E-915D-FEF25C772669/data/Containers/Data/Application/9517BBBB-E383-467E-B0E2-8960B734B239/Library/Application%20Support/delete.sqlite
options:(null) ...
returned error NSCocoaErrorDomain(512) with userInfo dictionary { reason = "Failed to create file; code = 2";
I'm on iOS 13.3 and Xcode 11.3. Does anyone know what's happening here?
The Application Support folder does not exist unless you explicitly create it. None of your code creates it. There's an NSFileManager method that will give you the NSApplicationSupportDirectory URL and create it (if it doesn't already exist) at the same time.
https://developer.apple.com/documentation/foundation/nsfilemanager/1407693-urlfordirectory?language=objc
I'm creating a NSPersistentStore with the code below.
NSPersistentStore * pc = [persistentCoordinator
addPersistentStoreWithType:EncryptedStoreType
configuration:nil
URL:databaseURL
options:options
error:error];
if (*error)
{
NSLog(#"Unable to add persistent store.");
NSLog(#"Error: %#\n%#\n%#", *error, [*error userInfo], [*error localizedDescription]);
}
The value of options is
{
EncryptedStore = SQLite;
EncryptedStoreDatabaseLocation =
"file:///var/mobile/Containers/Data/Application/0C27F628-3FF0-467F-8EF1-5974EBBD3620/Documents/DBEncrypted.sqlite";
EncryptedStorePassphrase = "xxxxxxxxredactedxxxxxxx";
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1;
NSSQLitePragmasOption = {
synchronous = OFF;
};
}
At this point *error is nil and pc is nil too.
According to Apple's documentation if the function returns nil should be an error. Does anyone saw it before?
The EncryptedStoreType is from https://github.com/project-imas/encrypted-core-data
The error only happens if we are migrating the Data Store
EDIT:
Full code of method:
+ (NSPersistentStoreCoordinator *)makeStoreWithOptions:(NSDictionary *)options managedObjectModel:(NSManagedObjectModel *)objModel error:(NSError *__autoreleasing *)error
{
NSPersistentStoreCoordinator * persistentCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objModel];
// NSString* appSupportDir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0];
BOOL backup = YES;
NSURL *databaseURL;
id dburl = [options objectForKey:EncryptedStoreDatabaseLocation];
if(dburl != nil) {
if ([dburl isKindOfClass:[NSString class]]){
databaseURL = [NSURL URLWithString:[options objectForKey:EncryptedStoreDatabaseLocation]];
backup = NO;
}
else if ([dburl isKindOfClass:[NSURL class]]){
databaseURL = dburl;
backup = NO;
}
}
if (backup){
NSString *dbNameKey = (__bridge NSString *)kCFBundleNameKey;
NSString *dbName = NSBundle.mainBundle.infoDictionary[dbNameKey];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *applicationSupportURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
[fileManager createDirectoryAtURL:applicationSupportURL withIntermediateDirectories:NO attributes:nil error:nil];
databaseURL = [applicationSupportURL URLByAppendingPathComponent:[dbName stringByAppendingString:#".sqlite"]];
}
[persistentCoordinator addPersistentStoreWithType:EncryptedStoreType configuration:nil URL:databaseURL
options:options error:error];
if (*error)
{
NSLog(#"Unable to add persistent store.");
NSLog(#"Error: %#\n%#\n%#", *error, [*error userInfo], [*error localizedDescription]);
}
return persistentCoordinator;
}
I call it in
- (void) initCoreDataProperties
{
NSError *error;
// Creating the Managed Object Model from momd
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:TBCoreDataModelFileName withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
// Creating the Encrypted Store Persistent Coordinator
_persistentStoreCoordinator = [EncryptedStore makeStoreWithOptions: [self persistentStoreOptions]
managedObjectModel: self.managedObjectModel
error: &error];
First, do not check the error for an error state. Only check the return of the call to -addPersistentStoreWithType.... The error can be populated even in a non-error condition.
Your code looks fine so I suspect if you turned off the encrypted store and used an Apple provided SQLite store then it would work fine. Which means the issue is with that third party code.
Since the third party code is not providing you with an error or a NSPersistentStore then it is failing poorly and you need to open a bug against the code base so that the author can address it.
Or you can walk through that third part code and see where it is failing and why.
I'm trying to prepopulate a coredata database from a sqlite file, but I don't understand why the database is not filled. My sqlite file is properly filled with all the data I need and added in the bundle ressources.
Here the persistentStoreCoordinator method int the AppDelegate :
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator != nil)
{
return persistentStoreCoordinator;
}
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingString:#"MyApp.db"];
NSError *error = nil;
NSFileManager *fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:storePath])
{
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"MyApp" ofType:#"db"];
if (defaultStorePath)
{
[fm 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]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
{
NSLog(#"Unresolved error : %#: %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}
In the view controller, I try to fetch the entries but it seems enter code hereempty :
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
initWithEntityName:#"Type_textimage_4text"];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *description = [NSEntityDescription entityForName:#"Type_textimage_4text" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:description];
NSMutableArray *questions = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
NSLog(#"question : %#", questions);
I probably missed something but I don't find what. Anyone can help me please ?
In answer to the coment above, I'm adding the AppDelegate.m file of one App which includes a prepopulated sqlite database. To do that I selected "Use Core Data" when I created the project on xcode. Although it works for me, I believe it is now a better praxis to use NSDocument for this kind of applications. One of the advantages is that the project is already on a good track to be iCloud compatible. I haven't done that yet, so I'm speaking only from what I've read/seen.
//
// AppDelegate.m
//
//
//
#import "AppDelegate.h"
#import "MainView.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize managedObjectContext = __managedObjectContext;
#synthesize managedObjectModel = __managedObjectModel;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navViewController = (UINavigationController *)self.window.rootViewController;
MainView *main=[[navViewController viewControllers]objectAtIndex:0];
main.managedObjectContext=self.managedObjectContext;
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#pragma mark - Core Data stack
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil) {
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Solvents" withExtension:#"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
- (NSString *)applicationDocumentsDirectoryString {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Solvents.sqlite"];
NSString *storePath = [[self applicationDocumentsDirectoryString] stringByAppendingPathComponent: #"Solvents.sqlite"];
//NSLog(#"store path %#", storePath);
//NSLog(#"store URL%#", storeURL );
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:storePath ]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"Solvents" 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;
}
#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];
}
#end
I'm trying to follow this tutorial:
http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-updated
In this tutorial show how build a script for create a sqlite and import data from json.
I have write this:
static NSManagedObjectModel *managedObjectModel()
{
static NSManagedObjectModel *model = nil;
if (model != nil) {
return model;
}
NSString *path = #"AppChecker";
path = [path stringByDeletingPathExtension];
NSURL *modelURL = [NSURL fileURLWithPath:[path stringByAppendingPathExtension:#"mom"]];
model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return model;
}
static NSManagedObjectContext *managedObjectContext()
{
static NSManagedObjectContext *context = nil;
if (context != nil) {
return context;
}
#autoreleasepool {
context = [[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel()];
[context setPersistentStoreCoordinator:coordinator];
NSString *STORE_TYPE = NSSQLiteStoreType;
NSString *path = [[NSProcessInfo processInfo] arguments][0];
path = [path stringByDeletingPathExtension];
NSURL *url = [NSURL fileURLWithPath:[path stringByAppendingPathExtension:#"sqlite"]];
NSError *error;
NSPersistentStore *newStore = [coordinator addPersistentStoreWithType:STORE_TYPE configuration:nil URL:url options:nil error:&error];
if (newStore == nil) {
NSLog(#"Store Configuration Failure %#", ([error localizedDescription] != nil) ? [error localizedDescription] : #"Unknown Error");
}
}
return context;
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
// Create the managed object context
NSManagedObjectContext *context = managedObjectContext();
// Custom code here...
// Save the managed object context
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Error while saving %#", ([error localizedDescription] != nil) ? [error localizedDescription] : #"Unknown Error");
exit(1);
}
NSError* err = nil;
NSString* dataPath = [[NSBundle mainBundle] pathForResource:#"brands" ofType:#"json"];
NSArray* Brands = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath]
options:kNilOptions
error:&err];
NSLog(#"Imported Brands: %#", Brands);
NSString* dataPath2 = [[NSBundle mainBundle] pathForResource:#"products" ofType:#"json"];
NSArray* Products = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath2]
options:kNilOptions
error:&err];
NSLog(#"Imported Products: %#", Products);
}
return 0;
}
The problem is that, it create the .sqlite database(and structure is ok), but there isn't data!!!
My db is so:
And this is my json of brands for example:
[{
"id":"1",
"name":"TestBrand",
"description":"",
"website":"",
"email":"",
"address":"",
"phone":"",
"from_country_list":"CZ",
"created_at":"2013-11-24 11:51:17.363473",
"updated_at":"2013-11-24 11:51:17.363473"
}]
Any help/tips on why the data isn't imported in .sqlite db ?
Thanks a lot.
Continue with the tutorial. You will have to iterate through your objects created from the JSON files and add each instance to the Core Data object graph, populate it with the available attributes and finally save the context.
Only after this last step will the data be stored in the sqlite database.
In my Application i have stored The core data file is saved in the app's Document directory
like this
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"App.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;}
How can i store the core data file inside the app's Library directory.
-(NSString*)applicationLibraryDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
NSPersistentStoreCoordinator *persistentStoreCoordinator;
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSError *error=nil;
NSString *storePath = [[self applicationLibraryDirectory] stringByAppendingPathComponent: #"sample.sqlite"];
NSURL *storeUrl =[NSURL fileURLWithPath:storePath];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
{
NSLog(#"store url %#",storeUrl);
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1);
}
return persistentStoreCoordinator;
}
NSURL *libraryDirectory = [NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *storeURL = [[self libraryDirectory] URLByAppendingPathComponent:#"App.sqlite"];
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{
NSPersistentStoreCoordinator *persistentStoreCoordinator;
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSError *error=nil;
NSString *storePath = [[self applicationLibraryDirectory] stringByAppendingPathComponent: #"Arivanza.sqlite"];
NSURL *storeUrl =[NSURL fileURLWithPath:storePath];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
{
NSLog(#"store url %#",storeUrl);
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1);
}
return persistentStoreCoordinator;
}
This Complete method solved my problem thanks for the help.