170 votes

iphone Core Data Unresolved error while saving (erreur de données non résolues lors de la sauvegarde)

Je reçois un étrange message d'erreur de la part des données de base lorsque j'essaie d'enregistrer mais le problème est que l'erreur n'est pas reproductible (elle apparaît à différents moments en effectuant différentes tâches).

le message d'erreur :

Unresolved error Domain=NSCocoaErrorDomain Code=1560 UserInfo=0x14f5480 "Operation could not be completed. (Cocoa error 1560.)", {
NSDetailedErrors = (
Error Domain=NSCocoaErrorDomain Code=1570 UserInfo=0x5406d70 "Operation could not be completed. (Cocoa error 1570.)",
Error Domain=NSCocoaErrorDomain Code=1570 UserInfo=0x14f9be0 "Operation could not be completed. (Cocoa error 1570.)"
);
}

et la méthode qui génère l'erreur est :

- (IBAction)saveAction:(id)sender {
    NSError *error;
    if (![[self managedObjectContext] save:&error]) {
        // Handle error
        NSLog(@"Unresolved error %@, %@, %@", error, [error userInfo],[error localizedDescription]);
        exit(-1);  // Fail
    }
}

une idée de la raison de ce message ? sachant qu'il apparaît à des moments aléatoires

0 votes

Cela pourrait vous aider : "Traitement des erreurs de "production" des données de base de l'iPhone". stackoverflow.com/questions/2262704/

298voto

David Wong Points 5773

Cela signifie qu'il y a une propriété obligatoire qui a été assignée à nil. Soit dans votre *.xcodatamodel cochez la case "optional" ou lorsque vous enregistrez dans le managedObjectContext assurez-vous que vos propriétés sont remplies.

Si vous obtenez d'autres erreurs après avoir modifié votre code pour l'adapter aux deux exigences, essayez de nettoyer votre compilation et de supprimer l'application de votre simulateur d'iPhone/appareil iPhone. Votre changement de modèle peut entrer en conflit avec l'implémentation de l'ancien modèle.

Editar:

J'allais oublier, voici tous les codes d'erreur que Core Data crache : Référence des constantes des données de base J'ai eu des problèmes avec cela auparavant et j'ai réalisé que j'avais décoché la bonne case facultative. C'est tellement difficile de trouver le problème. Bonne chance.

2 votes

Ceci a résolu le problème pour moi. Notez également qu'au moins dans mon expérience, même si les modifications n'ont pas été enregistrées dans le fichier sqlite, elles ont été intégrées dans le contexte. Le comportement peut donc être erratique lorsque cela se produit.

0 votes

Je n'ai pas pu trouver la cause première mais j'ai réussi à faire disparaître le problème en rendant toutes les propriétés facultatives.

0 votes

Avez-vous essayé le code de Charles, il vous indiquerait les champs qui posent problème.

235voto

Charles Points 2071

J'ai moi-même lutté contre ce problème pendant un certain temps. Le vrai problème ici est que le débogage que vous avez ne vous montre pas quel est le problème. La raison en est que CoreData place un tableau d'objets NSError dans l'objet NSError de "niveau supérieur" qu'il renvoie s'il y a plus d'un problème (c'est pourquoi vous voyez l'erreur 1560, qui indique plusieurs problèmes, et un tableau d'erreurs 1570). Il semble que CoreData dispose d'une poignée de clés qu'il utilise pour stocker des informations dans l'erreur qu'il renvoie s'il y a un problème qui vous donnera des informations plus utiles (comme l'entité sur laquelle l'erreur s'est produite, la relation/l'attribut qui manquait, etc.) Les clés que vous utilisez pour inspecter le dictionnaire userInfo se trouvent à l'endroit suivant les documents de référence ici .

Voici le bloc de code que j'utilise pour obtenir un résultat raisonnable à partir de l'erreur renvoyée lors d'une sauvegarde :

    NSError* error;
    if(![[survey managedObjectContext] save:&error]) {
        NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
        NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
        if(detailedErrors != nil && [detailedErrors count] > 0) {
            for(NSError* detailedError in detailedErrors) {
                NSLog(@"  DetailedError: %@", [detailedError userInfo]);
            }
        }
        else {
            NSLog(@"  %@", [error userInfo]);
        }
    }

Il produira un résultat qui vous indiquera les champs manquants, ce qui facilitera considérablement la résolution du problème.

0 votes

Merci beaucoup pour ce code. Il rend le suivi des problèmes de CoreData effectivement beaucoup plus simple.

21voto

clozach Points 991

Je présente ceci comme une réponse, même s'il s'agit plutôt d'un embellissement de l'extrait de Charles. La sortie directe de NSLog peut être un désordre à lire et à interpréter, donc j'aime ajouter des espaces blancs et rappeler la valeur de certaines clés 'userInfo' critiques.

Voici une version de la méthode que j'ai utilisée. ('_sharedManagedObjectContext' est un #define pour '[[[UIApplication sharedApplication] delegate] managedObjectContext]]').

- (BOOL)saveData {
    NSError *error;
    if (![_sharedManagedObjectContext save:&error]) {
        // If Cocoa generated the error...
        if ([[error domain] isEqualToString:@"NSCocoaErrorDomain"]) {
            // ...check whether there's an NSDetailedErrors array            
            NSDictionary *userInfo = [error userInfo];
            if ([userInfo valueForKey:@"NSDetailedErrors"] != nil) {
                // ...and loop through the array, if so.
                NSArray *errors = [userInfo valueForKey:@"NSDetailedErrors"];
                for (NSError *anError in errors) {

                    NSDictionary *subUserInfo = [anError userInfo];
                    subUserInfo = [anError userInfo];
                    // Granted, this indents the NSValidation keys rather a lot
                    // ...but it's a small loss to keep the code more readable.
                    NSLog(@"Core Data Save Error\n\n \
                      NSValidationErrorKey\n%@\n\n \
                      NSValidationErrorPredicate\n%@\n\n \
                      NSValidationErrorObject\n%@\n\n \
                      NSLocalizedDescription\n%@", 
                      [subUserInfo valueForKey:@"NSValidationErrorKey"], 
                      [subUserInfo valueForKey:@"NSValidationErrorPredicate"], 
                      [subUserInfo valueForKey:@"NSValidationErrorObject"], 
                      [subUserInfo valueForKey:@"NSLocalizedDescription"]);
                }
            }
            // If there was no NSDetailedErrors array, print values directly
            // from the top-level userInfo object. (Hint: all of these keys
            // will have null values when you've got multiple errors sitting
            // behind the NSDetailedErrors key.
            else {
                    NSLog(@"Core Data Save Error\n\n \
                      NSValidationErrorKey\n%@\n\n \
                      NSValidationErrorPredicate\n%@\n\n \
                      NSValidationErrorObject\n%@\n\n \
                      NSLocalizedDescription\n%@", 
                      [userInfo valueForKey:@"NSValidationErrorKey"], 
                      [userInfo valueForKey:@"NSValidationErrorPredicate"], 
                      [userInfo valueForKey:@"NSValidationErrorObject"], 
                      [userInfo valueForKey:@"NSLocalizedDescription"]);

            }
        } 
        // Handle mine--or 3rd party-generated--errors
        else {
            NSLog(@"Custom Error: %@", [error localizedDescription]);
        }
        return NO;
    }
    return YES;
}

Cela me permet de voir la valeur de 'NSValidationErrorKey', qui, lorsque j'ai rencontré le problème du PO, pointait directement vers les entités Core Data non optionnelles que j'avais oublié de définir avant d'essayer d'enregistrer.

0 votes

Également très utile. Surtout quand vous obtenez ce brut \n\n\n chaînes de description des entités de données de base.

0 votes

Neat. Le mot "message" est inutilisé.

0voto

HotJard Points 393

Le problème m'a touché, lorsque j'ai enregistré le deuxième enregistrement dans CoreData. Tous les champs non optionnels (relation) ont été remplis de nil également, mais dans la sortie d'erreur je remarquerais, qu'un des champs dans le premier objet sauvé était devenu nil. C'est un peu étrange ? Mais la raison est tout à fait triviale - une relation un à un qui annule le premier objet, lorsque je le mets dans le second.

Donc, le schéma est :

"Parent" with relationship "child" One to One
Create Child 1, set parent. Save - OK
Create Child 2, set parent. Save - Error, Child 1.Parent == nil
(behind the scene child 2 did nullify child 1 parent)

Le fait de changer la relation dans Parent de Un à Un à Plusieurs à Un a résolu cette tâche.

0voto

J'avais une propriété transitoire de type int qui n'était pas optionnelle. Évidemment, lorsqu'elle était définie sur 0, l'erreur 1570 apparaissait. J'ai juste changé toutes mes propriétés transitoires en facultatives. La logique de vérification du zéro peut être implémentée dans le code si nécessaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X