8

Hoping you can help. I'm adding Today support to my app, which uses MagicalRecord https://github.com/magicalpanda/MagicalRecord to managing all my CoreData stuff.

I'm tearing my hair out trying to understand how to surface my data into the Today extension.

I have enabled app groups as outlined here http://blog.sam-oakley.co.uk/post/92323630293/sharing-core-data-between-app-and-extension-in-ios-8 however all the documentation and StackOverflow posts I'm reading relate to using CoreData directly. MagicalRecord does a lot of the hard work for you, which is why I used it as I was totally new to it all at the beginning of this project. So things like:

Where you initialise your Core Data stack, you’ll be adding a store to your persistentStoreCoordinator a little something like this:

[persistentStoreCoordinator
addPersistentStoreWithType:NSSQLiteStoreType configuration:nil
URL:storeURL options:options error:&error]

It’s simply a matter of changing your previous value for storeURL (usually somewhere in NSDocumentDirectory) to a location contained in your shared App Group folder. You do this using

containerURLForSecurityApplicationGroupIdentifier: NSURL *directory =
[[NSFileManager defaultManager]
containerURLForSecurityApplicationGroupIdentifier:@"group.YourGroupName"];
NSURL *storeURL = [directory 
URLByAppendingPathComponent:@"YourAppName.sqlite"];

... I'm not understanding how / where to implement.

I'd imagined I'd just have to set up the MagicalRecord stack in my extension as I do in my appDelegate, but of course it's failing.

Really hoping someone might be in a similar situation and be able to shed some light on how to move forward with this one.

Any code you need to me to post up just let me know.

Thanks in advance

Kampai
  • 22,848
  • 21
  • 95
  • 95

3 Answers3

5

Not sure if this works on previous versions of MagicalRecord, but as of 2.2 you can just pass the final url as the store name:

NSFileManager *fileManager = [[NSFileManager alloc] init];

NSURL *directory = [fileManager containerURLForSecurityApplicationGroupIdentifier:@"group.yellow"];
NSURL *pathToStore = [directory URLByAppendingPathComponent:kMagicalRecordDefaultStoreFileName];

[MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:(id)pathToStore];
José Manuel Sánchez
  • 5,215
  • 2
  • 31
  • 24
4

I had the same problem I was able to fix it by following this thread. https://github.com/magicalpanda/MagicalRecord/issues/858

I first updated the following method in NSPersistentStore+MagicalRecord.m

- (NSURL *) MR_urlForStoreName:(NSString *)storeFileName
{
  NSFileManager *fileManager = [[NSFileManager alloc] init];

  NSURL *directory = [fileManager containerURLForSecurityApplicationGroupIdentifier:@"group.yourIdentifier"];
  NSURL *pathToStore = [directory URLByAppendingPathComponent:storeFileName];

  return pathToStore;

// NSArray *paths = [NSArray arrayWithObjects:[self MR_applicationDocumentsDirectory], [self MR_applicationStorageDirectory], nil];
// NSFileManager *fm = [[NSFileManager alloc] init];
//

// for (NSString *path in paths) 
// {
// NSString *filepath = [path stringByAppendingPathComponent:storeFileName];
// if ([fm fileExistsAtPath:filepath])
// {
// return [NSURL fileURLWithPath:filepath];
// }
// }
//
// return [NSURL fileURLWithPath:[[self MR_applicationStorageDirectory] stringByAppendingPathComponent:storeFileName]];
}

Then within my extension I just added the following to its view did load method.

- (void)viewDidLoad {
  [super viewDidLoad];
  [MagicalRecord setupCoreDataStackWithStoreNamed:<storeFileName>];
}
rowan.t
  • 187
  • 1
  • 10
  • That last part isn't @"group.yourIdentifier", it should be whatever you used for storeFileName. – jwhat Oct 09 '14 at 21:47
  • This actually causes core data to be empty if you release this as an update to an existing app. Looking for another solution... – jwhat Nov 23 '14 at 18:14
  • @jwhat Have you come across another solution? Can't seem to get this going for a keyboard extension. :\ – KingPolygon Jan 20 '15 at 13:01
3

Change

[MagicalRecord setupCoreDataStackWithStoreNamed:@"Database"];

to

 - (void)setupCoreDataStack
{
     if ([NSPersistentStoreCoordinator MR_defaultStoreCoordinator] != nil)
     {
        return;
    }

    NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];

    NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.yourgroup"];
    storeURL = [storeURL URLByAppendingPathComponent:@"Database.sqlite"];

    [psc MR_addSqliteStoreNamed:storeURL withOptions:nil];
    [NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:psc];
    [NSManagedObjectContext MR_initializeDefaultContextWithCoordinator:psc];
}
Igor
  • 4,235
  • 3
  • 34
  • 32
  • 1
    I like this idea, basically setting things up manually, but be careful. Your first line to check the defaultStoreCoordinator is set by default to automatically create a coordinator if one doesn't exist, so that will always be non-nil and none of the code below will run. If you want to do this, you'll need to add [MagicalRecordHelpers setShouldAutoCreateDefaultPersistentStoreCoordinator:NO]; to the very top of that method. – Cory Imdieke Mar 03 '15 at 19:40