web-dev-qa-db-fra.com

iphone Core Data Erreur non résolue lors de la sauvegarde

Je reçois un message d'erreur étrange des données principales lorsque j'essaie d'enregistrer Mais le problème est que l'erreur n'est pas reproductible (elle apparaît à différents moments lorsque vous effectuez des tâches différentes)

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 la suivante:

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

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

168
Ahmed Kotb

Cela signifie qu'une propriété obligatoire a été affectée à zéro. Soit dans votre * .xcodatamodel, cochez la case "facultatif" ou, lorsque vous enregistrez dans le managedObjectContext, assurez-vous que vos propriétés sont renseignées. 

Si vous rencontrez d'autres erreurs après avoir modifié votre code afin qu'il corresponde aux deux exigences, essayez de nettoyer votre version et supprimez l'application de votre iPhone Simulator/iPhone. Votre modification de modèle peut entrer en conflit avec l'ancienne implémentation du modèle.

Modifier:

J'ai presque oublié voici tous les codes d'erreur que Core Data a crachés: Référence des constantes Core Data Un tel problème pour trouver le problème. Bonne chance.

291
David Wong

J'ai lutté avec cela pendant un petit moment moi-même. Le vrai problème ici est que le débogage que vous avez ne vous indique pas quel est le problème. La raison en est que CoreData mettra un tableau d'objets NSError dans l'objet NSError "de niveau supérieur" qu'il renvoie s'il existe plusieurs problèmes (c'est pourquoi vous voyez l'erreur 1560, qui indique plusieurs problèmes, et un tableau d'erreur 1570). Il semble que CoreData utilise une poignée de clés pour cacher les informations dans l'erreur renvoyée si un problème vous donne des informations plus utiles (telles que l'entité sur laquelle l'erreur s'est produite, la relation/l'attribut manquant, etc. ). Les clés que vous utilisez pour inspecter le dictionnaire userInfo se trouvent dans les documents de référence ici .

C'est le bloc de code que j'utilise pour obtenir une sortie raisonnable 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 une sortie indiquant les champs manquants, ce qui facilite considérablement la résolution du problème.

232
Charles

J'y ajoute une réponse, même si c'est vraiment un embellissement de l'extrait de Charles. La sortie directe de NSLog peut être un désordre à lire et à interpréter, aussi j’aime bien insérer quelques espaces et appeler la valeur de certaines clés «userInfo» critiques.

Voici une version de la méthode que j'utilise. ('_sharedManagedObjectContext' est un #define pour '[[[[UIApplication sharedApplication]] délégué]] 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 de l'OP, a indiqué directement les entités non facultatives Core Data que j'avais oublié de définir avant de tenter de sauvegarder.

21
clozach

Ça m'a aidé. Vérifiez celui-ci aussi.

Cochez la case optional dans vos objets * .xcodatamodel

0
ssowri1

J'avais une propriété transitoire de type int qui n'était pas facultative. Évidemment, quand il était réglé sur 0, une erreur 1570 apparaît. Je viens de changer toutes mes propriétés transitoires en facultatif. La logique de contrôle nul peut être implémentée dans le code si nécessaire.

0
Anton Plebanovich

I signifie que votre modèle n'a pas pu être validé, ce qui peut arriver pour plusieurs raisons: propriété inutilisée dans votre modèle, valeur manquante marquée comme étant obligatoire .. où vous êtes prêt à enregistrer votre objet et appelez l’une des variantes de la méthode validateFor..., telle que:

po [myObject validateForInsert]

Des informations plus détaillées sur le problème se trouvent dans la description de l'erreur. Une validation réussie signifie que vous n’obtiendrez aucun résultat. 

0
kkodev

Le problème m'a touché lorsque j'ai sauvegardé le deuxième enregistrement dans CoreData. Tous les champs non facultatifs (relation) ont été remplis sans nil également, mais dans le résultat d'erreur, je remarquais que l'un des champs du premier objet enregistré était devenu nul. Étrange un peu? Mais la raison est assez triviale - une relation un à un qui annule le premier objet, lorsque je le mets dans le second.

Le schéma est donc:

"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)

Changer la relation dans le parent de un à un à plusieurs en un a résolu cette tâche.

0
HotJard