Import JSON into Core Data - ios

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.

Related

NSPersistentStoreCoordinator has no persistent stores (can't open)

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]

Core Data addPersistentStoreWithType return nil, but error is nil too

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.

How to transfer encrypted data over AirDrop

I want to transfer my NSObject "RND_PatientData" which is encrypted from my application to another person using the application using AirDrop.
At present my data is saved using this code:
- (RND_PatientData *)data {
if (_data != nil) return _data;
NSString *dataPath = [_docPath stringByAppendingPathComponent:kDataFile];
NSData *codedData = [[NSData alloc] initWithContentsOfFile:dataPath];
if (codedData == nil) return nil;
NSString *deviceName = [[UIDevice currentDevice] name];
NSData *decryptedData = [RNDecryptor decryptData:codedData withSettings:kRNCryptorAES256Settings password:deviceName error:nil];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:decryptedData];
_data = [unarchiver decodeObjectForKey:kDataKey];
[unarchiver finishDecoding];
return _data;
}
- (void)saveData {
if (_data == nil) return;
[self createDataPath];
NSString *dataPath = [_docPath stringByAppendingPathComponent:kDataFile];
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:_data forKey:kDataKey];
[archiver finishEncoding];
NSError *error;
NSString *deviceName = [[UIDevice currentDevice] name];
NSData *encryptedData = [RNEncryptor encryptData:data
withSettings:kRNCryptorAES256Settings
password:deviceName
error:&error];
[encryptedData writeToFile:dataPath atomically:YES];
This data is also encrypted using the device UDID and the RNDecryptor library before being saved.
Now, I would like the perosn to be able to transfer the data via AirDrop.
Is it better to decrypt the data on the sender phone and then transfer it unencrypted and encrypt it on the receiver phone using the same framework or to transfer it encrypted and decrypt it using the sender device UDID?
I load my current data as a NSMutableArray :
_patients = [RND_PatientDB loadDocs];
The method goes as follow:
+ (NSMutableArray *)loadDocs {
// Get private docs dir
NSString *documentsDirectory = [RND_PatientDB getPrivateDocsDir];
NSLog(#"Loading patients from %#", documentsDirectory);
// Get contents of documents directory
NSError *error;
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:&error];
if (files == nil) {
NSLog(#"Error reading contents of documents directory: %#", [error localizedDescription]);
return nil;
}
// Create Patients for each file
NSMutableArray *retval = [NSMutableArray arrayWithCapacity:files.count];
for (NSString *file in files) {
if ([file.pathExtension compare:#"patients" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:file];
RND_Patient *doc = [[RND_Patient alloc] initWithDocPath:fullPath];
[retval addObject:doc];
}
}
return retval;
}
+ (NSString *)nextPatientDocPath {
// Get private docs dir
NSString *documentsDirectory = [RND_PatientDB getPrivateDocsDir];
// Get contents of documents directory
NSError *error;
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:&error];
if (files == nil) {
NSLog(#"Error reading contents of documents directory: %#", [error localizedDescription]);
return nil;
}
// Search for an available name
int maxNumber = 0;
for (NSString *file in files) {
if ([file.pathExtension compare:#"patients" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
NSString *fileName = [file stringByDeletingPathExtension];
maxNumber = MAX(maxNumber, fileName.intValue);
}
}
// Get available name
NSString *availableName = [NSString stringWithFormat:#"%d.patients", maxNumber+1];
return [documentsDirectory stringByAppendingPathComponent:availableName];
}
I've tried following instructions here to send NSArray via AirDrop, but I cannot understand how the certificate works. Anyone has ressources I can use to learn more about this procedure? Also am I doing it the right way or is there an easier method to send my NSMutableArray of _patients comprised of RND_PATIENT NSObject to another person using my application?

Coredata database prepopulation is not filled

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

NSDictionary to File

I have been working on a SOAP Web Service that uses a Caché to avoid HTTP requests when they have been done before.
When I try to save my NSDictionary to a file I get a error (I guess it is because it doesn't follow the Properties List structure) and I know how to fix it.
This is my code:
[self loadCache];
NSData *responseData;
NSMutableDictionary* dict = [_cache objectForKey:delegate.type];
if (dict != nil && [dict objectForKey:request.HTTPBody] != nil ) {
responseData = [dict objectForKey:request.HTTPBody];
} else {
NSHTTPURLResponse* urlResponse = nil;
NSError *error = [[NSError alloc] init];
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
if (dict == nil) {
dict = [[NSMutableDictionary alloc] init];
[_cache setObject:dict forKey:delegate.type];
[dict setObject:[NSNumber numberWithDouble:NSTimeIntervalSince1970] forKey:#"FECHA"];
}
if (responseData == nil) {
responseData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"test" ofType:#"xml"]];
}
NSLog(#"%#", [[request.HTTPBody copy] class]);
[dict setObject:responseData forKey:request.HTTPBody];
[self saveCache];
}
loadCache Function:
- (void)loadCache {
if (_loadedCache) return;
NSString* docsurl = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
docsurl = [docsurl stringByAppendingPathComponent:#"cache.txt"];
_cache = [[NSMutableDictionary alloc] initWithContentsOfFile:docsurl];
if (_cache == nil) _cache = [[NSMutableDictionary alloc] init];
}
saveCache Function:
- (void)saveCache {
NSString* docsurl = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
docsurl = [docsurl stringByAppendingPathComponent:#"cache.txt"];
if ([_cache writeToFile:docsurl atomically:YES]) {
NSLog(#"SAVED");
} else {
NSLog(#"ERROR");
}
}
NSData cannot be the "key" it is only able to be the "value"
As commented: Solved! I was trying to use NSData as KEY, and it can only be used as VALUE.

Resources