iphone Core Data Ungelöster Fehler beim Speichern

169

Ich erhalte eine seltsame Fehlermeldung von den Kerndaten, wenn ich versuche zu speichern, aber das Problem, dass der Fehler nicht reproduzierbar ist (er tritt zu unterschiedlichen Zeiten auf, wenn verschiedene Aufgaben ausgeführt werden).

die Fehlermeldung:

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

und die Methode, die den Fehler erzeugt, ist:

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

Irgendeine Idee für den Grund dieser Nachricht? geben, dass es zu zufälligen Zeiten erscheint

Ahmed Kotb
quelle
Dies könnte Ihnen helfen: "iPhone Core Data" Produktion " Fehlerbehandlung
Johannes Fahrenkrug

Antworten:

296

Dies bedeutet, dass eine obligatorische Eigenschaft mit Null zugewiesen wurde. Aktivieren Sie entweder in Ihrem * .xcodatamodel das Kontrollkästchen "optional" oder stellen Sie beim Speichern im ManagedObjectContext sicher, dass Ihre Eigenschaften ausgefüllt sind.

Wenn Sie nach dem Ändern Ihres Codes weitere Fehler erhalten, versuchen Sie, Ihren Build zu bereinigen und die Anwendung von Ihrem iPhone Simulator / iPhone-Gerät zu löschen. Ihre Modelländerung kann mit der alten Modellimplementierung in Konflikt stehen.

Bearbeiten:

Ich habe fast vergessen, dass hier alle Fehlercodes sind, die Core Data ausspuckt: Core Data Constants Reference Ich hatte zuvor Probleme damit und stellte fest, dass ich das richtige optionale Kontrollkästchen deaktiviert habe. Solche Probleme, das Problem herauszufinden. Viel Glück.

David Wong
quelle
2
Das hat es für mich gelöst. Beachten Sie auch, dass zumindest meiner Erfahrung nach die Änderungen in den Kontext gelangt sind, obwohl sie nicht in der SQLite-Datei gespeichert wurden. Daher kann das Verhalten in diesem Fall unberechenbar sein.
Nickthedude
Ich konnte die Ursache nicht finden, aber ich habe es geschafft, das Problem zu beheben, indem ich alle Eigenschaften optional gemacht habe.
Michael Osofsky
Haben Sie Charles 'Code ausprobiert, würde er Ihnen sagen, welches Feld das Problem ist.
David Wong
233

Ich selbst hatte eine Weile damit zu kämpfen. Das eigentliche Problem hierbei ist, dass das Debugging Ihnen nicht zeigt, wo das Problem liegt. Der Grund dafür ist, dass CoreData ein Array von NSError-Objekten in das NSError-Objekt der "obersten Ebene" einfügt, das zurückgegeben wird, wenn mehr als ein Problem vorliegt (Aus diesem Grund wird der Fehler 1560 angezeigt, der auf mehrere Probleme hinweist, sowie ein Fehlerarray 1570er Jahre). Es scheint, dass CoreData über eine Handvoll Schlüssel verfügt, mit denen Informationen in dem zurückgegebenen Fehler gespeichert werden, wenn ein Problem auftritt, das Ihnen nützlichere Informationen liefert (z. B. die Entität, bei der der Fehler aufgetreten ist, die Beziehung / das fehlende Attribut usw. ). Die Schlüssel, mit denen Sie das userInfo-Wörterbuch überprüfen, finden Sie in den Referenzdokumenten hier .

Dies ist der Codeblock, den ich verwende, um eine angemessene Ausgabe des Fehlers zu erhalten, der während eines Speichervorgangs zurückgegeben wird:

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

Es wird eine Ausgabe erstellt, die Ihnen sagt, welche Felder fehlen, wodurch die Behebung des Problems erheblich einfacher zu handhaben ist.

Charles
quelle
Vielen Dank für diesen Code. Dies macht die Verfolgung von CoreData-Problemen in der Tat viel einfacher.
MiKL
21

Ich werfe dies als Antwort ein, obwohl es wirklich eher eine Verschönerung von Charles 'Ausschnitt ist. Die direkte Ausgabe von NSLog kann ein Chaos beim Lesen und Interpretieren sein, daher mag ich es, Leerzeichen einzufügen und den Wert einiger kritischer 'userInfo'-Schlüssel aufzurufen.

Hier ist eine Version der Methode, die ich verwendet habe. ('_sharedManagedObjectContext' ist eine #Definition für '[[UIApplication sharedApplication] delegate] manageObjectContext]'.)

- (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;
}

Auf diese Weise kann ich den Wert für 'NSValidationErrorKey' anzeigen, der, als ich auf das Problem im OP stieß, direkt auf die nicht optionalen Core Data-Entitäten zeigte, die ich vor dem Speichern vergessen hatte, festzulegen.

Clozach
quelle
Auch sehr nützlich. Insbesondere, wenn Sie diese rohen \ n \ n \ n Beschreibungszeichenfolgen für Kerndatenentitäten erhalten.
Lukasz
Ordentlich. 'message' wird übrigens nicht verwendet.
Pojo
0

Das Problem hat mich berührt, als ich den zweiten Datensatz in CoreData speichere. Alle nicht optionalen Felder (Beziehung) wurden ebenfalls ohne Null gefüllt, aber in der Fehlerausgabe würde ich feststellen, dass eines der Felder im ersten gespeicherten Objekt Null geworden war. Seltsam ein bisschen? Aber der Grund ist ziemlich trivial - eine Eins-zu-Eins-Beziehung, die das erste Objekt zunichte macht, wenn ich es in das zweite setze.

Das Schema lautet also:

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

Das Ändern der Beziehung in Eltern von Eins zu Eins zu Viele zu Eins löste diese Aufgabe.

HotJard
quelle
0

Ich hatte eine vorübergehende Eigenschaft vom Typ int, die nicht optional war. Wenn es auf 0 gesetzt wurde, erscheint offensichtlich ein 1570-Fehler. Ich habe gerade alle meine vorübergehenden Eigenschaften in optional geändert. Bei Bedarf kann die Nil-Check-Logik im Code implementiert werden.

Anton Plebanovich
quelle
0

Ich meine, Ihr Modell konnte nicht validiert werden, was aus verschiedenen Gründen auftreten kann: Nicht verwendete Eigenschaft in Ihrem Modell, fehlender Wert, der als erforderlich markiert ist. Um besser zu verstehen, was genau schief gelaufen ist, platzieren Sie einen Haltepunkt an einer Stelle, an der Sie bereit sind, Ihr Objekt zu speichern, und rufen Sie eine der validateFor...Methodenvarianten auf, z.

po [myObject validateForInsert]

Weitere Informationen zum Problem finden Sie in der Fehlerbeschreibung. Erfolgreiche Validierung bedeutet, dass Sie keine Ausgabe erhalten.

kkodev
quelle
0

Es hat mir geholfen. Überprüfen Sie auch diesen.

Aktivieren Sie das optionale Kontrollkästchen in Ihren * .xcodatamodel-Objekten

ssowri1
quelle