iPhone Core Data Nierozwiązany błąd podczas zapisywania


169

Otrzymuję dziwny komunikat o błędzie z podstawowych danych podczas próby zapisania, ale problem polega na tym, że błąd nie jest odtwarzalny (pojawia się w różnym czasie podczas wykonywania różnych zadań)

komunikat o błędzie:

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

a metoda generująca błąd to:

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

jakiś pomysł na powód tej wiadomości? dając, że pojawia się losowo


To może ci pomóc: „Obsługa błędów danych podstawowych iPhone'a„ Produkcja ”” stackoverflow.com/questions/2262704/ ...
— Johannes Fahrenkrug

Odpowiedzi:


296

Oznacza to, że przypisano zerową właściwość obowiązkową. Albo w swoim * .xcodatamodelu zaznacz pole „opcjonalne” lub podczas zapisywania w managedObjectContext upewnij się, że Twoje właściwości są wypełnione.

Jeśli po zmianie kodu w celu dopasowania do dwóch wymagań pojawiają się kolejne błędy, spróbuj wyczyścić kompilację i usunąć aplikację z urządzenia iPhone Simulator / iPhone. Twoja zmiana modelu może kolidować ze starą implementacją modelu.

Edytować:

Prawie zapomniałem o wszystkich kodach błędów, które wypluwa Core Data: Odniesienie do stałych danych podstawowych : Miałem z tym wcześniej problem i zdałem sobie sprawę, że odznaczyłem poprawne opcjonalne pole. Taki problem ze znalezieniem problemu. Powodzenia.


2
To rozwiązało to dla mnie. Zauważ również, że przynajmniej z mojego doświadczenia, mimo że nie został zapisany w pliku sqlite, zmiany dotarły do ​​kontekstu. W takim przypadku zachowanie może być nieobliczalne.
— nickthedude

Nie udało mi się dotrzeć do głównej przyczyny, ale udało mi się rozwiązać problem, ustawiając wszystkie właściwości jako opcjonalne.
— Michael Osofsky

Czy wypróbowałeś kod Charlesa, powiedziałby ci, w którym polu występuje problem.
— David Wong,

233

Sam przez chwilę z tym walczyłem. Prawdziwy problem polega na tym, że debugowanie, które masz, nie pokazuje, na czym polega problem. Powodem tego jest to, że CoreData umieści tablicę obiektów NSError w obiekcie NSError "najwyższego poziomu", który zwraca, jeśli jest więcej niż jeden problem (dlatego pojawia się błąd 1560, który wskazuje wiele problemów i tablicę błędów 1570). Wygląda na to, że CoreData ma kilka kluczy, których używa do przechowywania informacji w zwracanym błędzie, jeśli wystąpi problem, który da ci bardziej przydatne informacje (takie jak encja, w której wystąpił błąd, związek / atrybut, którego brakowało itp. ). Klucze używane do sprawdzania słownika informacji o użytkowniku można znaleźć w dokumentacji referencyjnej tutaj .

Oto blok kodu, którego używam, aby uzyskać rozsądne dane wyjściowe z błędu zwróconego podczas zapisywania:

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

Spowoduje to wyświetlenie danych wyjściowych z informacją o brakujących polach, co znacznie ułatwia rozwiązanie problemu.


Wielkie dzięki za ten kod. To sprawia, że ​​śledzenie problemów w CoreData jest rzeczywiście znacznie prostsze.
— MiKL

21

Wrzucam to jako odpowiedź, chociaż jest to bardziej upiększenie fragmentu Charlesa. Proste wyjście z NSLog może być bałaganem do odczytania i zinterpretowania, więc lubię dorzucić trochę białych znaków i wywołać wartość niektórych krytycznych kluczy „userInfo”.

Oto wersja metody, której używałem. („_sharedManagedObjectContext” to #define dla „[[[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;
}

To pozwala mi zobaczyć wartość `` NSValidationErrorKey '', która, gdy napotkałem problem z OP, wskazywała bezpośrednio na nie opcjonalne jednostki Core Data, których zapomniałem ustawić przed próbą zapisania.


Również bardzo przydatne. Szczególnie, gdy otrzymujesz te surowe \ n \ n \ n ciągi opisujące podstawowe jednostki danych.
— Łukasz

Schludny. Przy okazji „wiadomość” jest nieużywana.
— pojo

0

Problem dotknął mnie, kiedy zapisuję drugi rekord w CoreData. Wszystkie pola nieobowiązkowe (relacja) zostały również wypełnione bez zera, ale w wyniku błędu zauważyłem, że jedno z pól w pierwszym zapisanym obiekcie stało się zerowe. Trochę dziwne? Ale powód jest dość banalny - relacja jeden do jednego, która unieważnia pierwszy obiekt, gdy ustawię go w drugim.

Tak więc schemat jest taki:

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

Zmiana relacji w Rodzinie z Jeden na Jeden na Wiele w Jeden rozwiązała to zadanie.


0

Miałem przejściową właściwość typu int, która nie była opcjonalna. Oczywiście przy ustawieniu na 0 pojawia się błąd 1570. Właśnie zmieniłem wszystkie moje właściwości przejściowe na opcjonalne. W razie potrzeby można zaimplementować w kodzie logikę zerową.


0

Oznacza to, że Twój model nie został zweryfikowany, co może się zdarzyć z wielu powodów: nieużywana właściwość w modelu, brakująca wartość oznaczona jako wymagana. Aby lepiej zrozumieć, co poszło nie tak, ustaw punkt przerwania w miejscu, w którym jesteś gotowy do zapisania obiektu, i wywołaj jeden z validateFor...wariantów metody, na przykład:

po [myObject validateForInsert]

Bardziej szczegółowe informacje o problemie znajdują się w opisie błędu. Pomyślna weryfikacja oznacza, że ​​nie otrzymasz żadnych wyników.


0

Pomogło mi. Sprawdź też to.

Zaznacz opcjonalne pole w obiektach * .xcodatamodel

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.