web-dev-qa-db-fra.com

Accès à la base de données SQL Core Data dans l'extension iOS 8 (partage de données entre l'application et l'extension de widget)

Problème:

Impossible d'accéder à la base de données Core Data de l'application à partir d'une extension de widget dans la vue Aujourd'hui.

L'application elle-même est capable de lire et d'écrire dans la base de données comme d'habitude sous iOS 8, mais l'extension ne parviendra pas à créer le magasin, donnant l'erreur, incapable d'écrire dans le fichier.

Le journal est le suivant:

Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)"

reason = "Failed to create file; code = 2
34
Mark Bridges

Les widgets ne peuvent pas accéder au répertoire NSDocuments, qui est l'endroit où l'on stocke normalement sa base de données.

La solution consiste à créer d'abord un groupe d'applications

Allez à: Projet - Cible - Groupes d'applications - Ajouter un nouveau conteneur

Nommez le conteneur, c'est-à-dire 'group.mycontainer'

Répétez le processus pour la cible du widget en utilisant le même nom pour le conteneur.

Ensuite, écrivez votre base de données dans votre conteneur de groupe.

Donc:

NSURL *storeURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory  inDomains:NSAllDomainsMask] lastObject];
storeURL = [storeURL URLByAppendingPathComponent:@"db.sqlite"];

Devient:

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

Et l'initialisation du magasin devrait ressembler à ceci:

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

NSPersistentStore *store = nil;
store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                  configuration:nil
                                            URL:storeURL
                                        options:nil
                                          error:&error]
69
Mark Bridges

Je viens de comprendre que les fichiers du groupe d'applications ne sont pas sauvegardés à l'aide de la procédure de sauvegarde iOS standard.

Gardez à l'esprit que l'utilisateur peut perdre toutes ses données d'application après la restauration d'iOS si vous conservez le magasin persistant dans un conteneur de groupe d'applications.

MISE À JOUR

rdar: // 18750178

MISE À JOUR

semble résolu dans iOS 8.1, Apple m'ont envoyé un message et ont demandé de vérifier le problème dans iOS 8.1, qu'il soit corrigé ou non (assez impudent non?). Je ne l'ai pas testé, alors gardez à l'esprit. Quoi qu'il en soit, conserver le stockage dans AppGroups est une idée morte au cas où vous prendriez en charge iOS 8.0 défectueux

7
kas-kad

Changement

[MagicalRecord setupCoreDataStackWithStoreNamed:@"Database"];

à

 - (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];
}
5
Igor

La même chose pour Swift:

private func setupCoreDataStack() {

    if NSPersistentStoreCoordinator.MR_defaultStoreCoordinator() != nil {
        return
    }

    let managedObjectModel = NSManagedObjectModel.MR_defaultManagedObjectModel()
    let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
    var storePath = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier(PBOSharedSuiteGroupName)
    storePath = storePath!.URLByAppendingPathComponent("AppName.sqlite")

    var error: NSError?
    persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storePath, options: nil, error: &error)
    NSPersistentStoreCoordinator.MR_setDefaultStoreCoordinator(persistentStoreCoordinator)
    NSManagedObjectContext.MR_initializeDefaultContextWithCoordinator(persistentStoreCoordinator)
}

N'oubliez pas d'attacher cette méthode aux deux: AppDelegate et Today Extension