iphone Core Data Errore irrisolto durante il salvataggio


169

Ricevo uno strano messaggio di errore dai dati di base quando provo a salvare ma il problema è che l'errore non è riproducibile (appare in momenti diversi quando si eseguono attività diverse)

il messaggio di errore:

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.)"
);
}

e il metodo che genera l'errore è:

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

qualche idea per la ragione di questo messaggio? dando che appare in momenti casuali


Questo potrebbe aiutarti: "Gestione degli errori di" produzione "dei dati di base di iPhone" stackoverflow.com/questions/2262704/…
Johannes Fahrenkrug

Risposte:


296

Significa che è stata assegnata una proprietà obbligatoria nulla. O nel tuo * .xcodatamodel seleziona la casella "opzionale" o quando stai salvando su managedObjectContext assicurati che le tue proprietà siano compilate.

Se ricevi ulteriori errori dopo aver modificato il codice per soddisfare i due requisiti, prova a pulire la build ed elimina l'applicazione dal tuo simulatore iPhone / dispositivo iPhone. La modifica del modello potrebbe essere in conflitto con l'implementazione del vecchio modello.

Modificare:

Ho quasi dimenticato che ecco tutti i codici di errore emessi da Core Data: Riferimento di Costanti Core Data Ho avuto problemi con questo prima e mi sono reso conto di aver deselezionato la casella opzionale corretta. Tale difficoltà a scoprire il problema. In bocca al lupo.


2
Questo mi ha risolto. Si noti inoltre che almeno nella mia esperienza anche se non è stato salvato nel file sqlite, le modifiche si sono fatte strada nel contesto. Quindi il comportamento può essere irregolare quando ciò accade.
Nickthedude,

Non sono riuscito a trovare la causa principale, ma sono riuscito a risolvere il problema rendendo tutte le proprietà facoltative.
Michael Osofsky,

Hai provato il codice di Charles, ti direbbe quale campo è il problema.
David Wong,

233

Ho lottato con questo per un po 'di me stesso. Il vero problema qui è che il debug che hai non ti mostra quale sia il problema. Il motivo di ciò è perché CoreData inserirà una matrice di oggetti NSError nell'oggetto NSError "di livello superiore" che restituisce se si verifica più di un problema (ecco perché viene visualizzato l'errore 1560, che indica più problemi e una matrice di errori 1570s). Sembra che CoreData abbia una manciata di chiavi che utilizza per nascondere le informazioni nell'errore che restituisce se c'è un problema che ti darà informazioni più utili (come l'entità in cui si è verificato l'errore, la relazione / l'attributo mancante, ecc. ). Le chiavi utilizzate per ispezionare il dizionario userInfo sono disponibili nei documenti di riferimento qui .

Questo è il blocco di codice che utilizzo per ottenere un output ragionevole dall'errore restituito durante un salvataggio:

    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]);
        }
    }

Produrrà un output che ti dirà i campi mancanti, il che semplifica notevolmente la risoluzione del problema.


Grazie mille per questo codice. Rende il monitoraggio dei problemi di CoreData davvero molto più semplice.
MiKL

21

Lo sto dando come una risposta, anche se è davvero più di un abbellimento allo snippet di Charles. L'output diretto da NSLog può essere un disastro da leggere e interpretare, quindi mi piace gettare uno spazio bianco e richiamare il valore di alcune chiavi "userInfo" critiche.

Ecco una versione del metodo che ho usato. ('_sharedManagedObjectContext' è un #define per '[[[[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;
}

Questo mi permette di vedere il valore di "NSValidationErrorKey", che, quando ho riscontrato il problema dall'OP, puntava direttamente alle entità di dati core non opzionali che avevo dimenticato di impostare prima di provare a salvare.


Anche molto utile. Soprattutto quando si ottengono queste stringhe di descrizione dell'entità dati di base grezzi \ n \ n \ n.
Lukasz,

Neat. 'messaggio' non è utilizzato tra l'altro.
Pojo,

0

Il problema mi ha toccato quando ho salvato il secondo record su CoreData. Tutti i campi non facoltativi (relazione) sono stati compilati anche senza zero, ma nell'output dell'errore noterei che uno dei campi nel primo oggetto salvato era diventato nullo. Strano un po '? Ma la ragione è piuttosto banale: una relazione uno a uno che annulla il primo oggetto, quando l'ho impostato nel secondo.

Quindi, lo schema è:

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

La modifica della relazione in Parent da Uno a uno a Molti a uno ha risolto questo compito.


0

Avevo proprietà temporanee di tipo int che non erano facoltative. Ovviamente, quando era impostato su 0, appare l'errore 1570. Ho appena cambiato tutte le mie proprietà temporanee in facoltativo. Se necessario, la logica zero-check può essere implementata nel codice.


0

Voglio dire che il tuo modello non è riuscito a convalidare, il che potrebbe accadere per una serie di motivi: proprietà inutilizzata nel tuo modello, valore mancante contrassegnato come richiesto. Per comprendere meglio cosa è andato esattamente storto, posiziona un punto di interruzione in un punto in cui sei pronto a salvare l'oggetto e chiama una delle validateFor...varianti del metodo, come:

po [myObject validateForInsert]

Informazioni più dettagliate sul problema si trovano nella descrizione dell'errore. Convalida riuscita significa che non otterrai alcun output.


0

Mi ha aiutato Controlla anche questo.

Seleziona la casella opzionale negli oggetti * .xcodatamodel

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.