Erreur non résolue des données de base de l'iphone lors de l'enregistrement

169

Je reçois un message d'erreur étrange à partir des données de base lors de la tentative de sauvegarde, mais le problème est que l'erreur n'est pas reproductible (elle apparaît à des moments différents lors de 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 pour la raison de ce message? étant donné qu'il apparaît à des moments aléatoires

Ahmed Kotb
la source
Cela pourrait vous aider: "Traitement des erreurs de production" iPhone Core Data " stackoverflow.com/questions/2262704/...
Johannes Fahrenkrug

Réponses:

296

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

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

Éditer:

J'ai presque oublié ici tous les codes d'erreur crachés par Core Data: Référence des constantes de données de base J'ai eu des problèmes avec cela avant et j'ai réalisé que j'avais décoché la bonne case facultative. Une telle difficulté à découvrir le problème. Bonne chance.

David Wong
la source
2
Cela a résolu le problème pour moi. Notez également qu'au moins d'après mon expérience, même s'il n'a pas été enregistré dans le fichier sqlite, les modifications ont fait leur chemin dans le contexte. Le comportement peut donc être erratique lorsque cela se produit.
nickthedude
Je n'ai pas pu trouver la cause principale, mais j'ai réussi à résoudre le problème en rendant toutes les propriétés facultatives.
Michael Osofsky
Avez-vous essayé le code de Charles, il vous dirait quel champ est le problème.
David Wong
233

J'ai lutté avec ça pendant un petit moment moi-même. 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 placera un tableau d'objets NSError dans l'objet NSError de "niveau supérieur" qu'il retourne 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'erreur 1570s). Il semble que CoreData dispose d'une poignée de clés qu'il utilise pour cacher des informations dans l'erreur qu'il renvoie s'il y a un problème qui vous donnera 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 qui vous indiquera les champs manquants, ce qui facilitera considérablement la résolution du problème.

Charles
la source
Merci beaucoup pour ce code. Cela rend le suivi des problèmes CoreData beaucoup plus simple.
MiKL du
21

Je jette cela comme une réponse, même si c'est vraiment plus un embellissement à l'extrait de Charles. La sortie directe de NSLog peut être un désordre à lire et à interpréter, donc j'aime ajouter un espace blanc et appeler la valeur de certaines clés critiques «userInfo».

Voici une version de la méthode que j'ai utilisée. ('_sharedManagedObjectContext' est une #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 de l'OP, pointait directement vers les entités Core Data non facultatives que j'avais oublié de définir avant d'essayer de sauvegarder.

Clozach
la source
Aussi très utile. Surtout lorsque vous obtenez ces chaînes de description d'entité de données \ n \ n \ n de base brutes.
Lukasz
Soigné. «message» est inutilisé btw.
pojo
0

Le problème m'a touché lorsque j'enregistre le deuxième enregistrement dans CoreData. Tous les champs non facultatifs (relation) ont également été remplis sans zéro, mais dans la sortie d'erreur, je remarquerais que l'un des champs du premier objet enregistré était devenu nul. Un peu étrange? Mais la raison est assez triviale - une relation un à un qui annule le premier objet, lorsque je le place 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)

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

HotJard
la source
0

J'avais une propriété transitoire de type int qui n'était pas facultative. De toute évidence, lorsqu'il a été défini sur 0, une erreur de 1570 apparaît. Je viens de changer toutes mes propriétés transitoires en optionnelles. La logique de contrôle nul peut être implémentée dans le code si nécessaire.

Anton Plebanovich
la source
0

Je veux dire que votre modèle n'a pas pu être validé, ce qui peut se produire pour plusieurs raisons: propriété inutilisée dans votre modèle, valeur manquante marquée comme requise. Pour mieux comprendre ce qui n'a pas fonctionné, placez un point d'arrêt à un endroit où vous êtes prêt à enregistrer votre objet et appelez l'une des validateFor...variantes de méthode, comme:

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 aucune sortie.

kkodev
la source
0

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

Cochez la case facultative dans vos objets * .xcodatamodel

ssowri1
la source