iphone Core Data Неразрешенная ошибка при сохранении

169

Я получаю странное сообщение об ошибке из основных данных при попытке сохранить, но проблема в том, что ошибка не воспроизводима (она появляется в разное время при выполнении разных задач)

сообщение об ошибке:

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

и метод, который генерирует ошибку:

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

Любая идея по причине этого сообщения? давая, что это появляется в случайное время

Ахмед Котб
источник
Это может помочь вам: «Ошибка обработки основных данных iPhone« Обработка ошибок » stackoverflow.com/questions/2262704/…
Йоханнес Фаренкруг

Ответы:

296

Это означает, что обязательному свойству присвоено ноль. Либо в вашем * .xcodatamodel установите флажок «опционально», либо при сохранении в managedObjectContext убедитесь, что ваши свойства заполнены.

Если после изменения кода в соответствии с двумя требованиями появляются дальнейшие ошибки, попробуйте очистить сборку и удалите приложение с устройства iPhone Simulator / iPhone. Изменение вашей модели может конфликтовать с реализацией старой модели.

Редактировать:

Я почти забыл вот все коды ошибок, которые выдают Core Data: Справочник по константам Core Data У меня были проблемы с этим раньше, и я понял, что снял галочку с правильного дополнительного поля. Такая проблема, выясняя проблему. Удачи.

Дэвид Вонг
источник
2
Это решило это для меня. Также обратите внимание, что, по крайней мере, по моему опыту, несмотря на то, что он не был сохранен в файле sqlite, изменения попали в контекст. Таким образом, поведение может быть ошибочным, когда это происходит.
nickthedude
Я не мог найти причину, но мне удалось устранить проблему, сделав все свойства необязательными.
Майкл Ософски
Пробовал ли ты код Чарльза, он скажет тебе, в каком поле проблема.
Дэвид Вонг
233

Я боролся с этим некоторое время сам. Настоящая проблема здесь в том, что отладка, которая у вас есть, не показывает вам, в чем проблема. Причина этого заключается в том, что CoreData поместит массив объектов NSError в объект NSError «верхнего уровня», который он возвращает, если существует более одной проблемы (поэтому вы видите ошибку 1560, которая указывает на множественные проблемы, и массив ошибок 1570). Похоже, что у CoreData есть несколько ключей, которые он использует для хранения информации в ошибке, которую он возвращает, если есть проблема, которая даст вам более полезную информацию (например, сущность, в которой произошла ошибка, отсутствующее отношение / атрибут и т. Д. ). Ключи, которые вы используете для проверки словаря userInfo, можно найти в справочных документах здесь .

Это блок кода, который я использую для получения разумного вывода об ошибке, возвращенной во время сохранения:

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

Он выдаст вывод, который сообщит вам о пропущенных полях, что значительно облегчит решение проблемы.

Чарльз
источник
Большое спасибо за этот код. Это значительно упрощает отслеживание проблем CoreData.
MiKL
21

Я добавлю это в качестве ответа, хотя это действительно больше приукрашивание фрагмента Чарльза. Прямой вывод из NSLog может быть беспорядком для чтения и интерпретации, поэтому я хотел бы добавить некоторые пробелы и вызвать значение некоторых важных ключей 'userInfo'.

Вот версия метода, который я использовал. ('_sharedManagedObjectContext' является #define для '[[[UIApplication sharedApplication] делегат] 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;
}

Это позволяет мне увидеть значение NSValidationErrorKey, которое, когда я столкнулся с проблемой из OP, указывало непосредственно на необязательные сущности Core Data, которые я забыл установить перед попыткой сохранить.

clozach
источник
Также очень полезно. Особенно, когда вы получаете эти необработанные \ n \ n \ n строки описания сущности основных данных.
Лукаш
Ухоженная. «Сообщение» не используется между прочим.
pojo
0

Проблема коснулась меня, когда я сохранил вторую запись в CoreData. Все необязательные поля (отношения) также были заполнены без нуля, но в выводе ошибки я заметил, что одно из полей в первом сохраненном объекте стало нулем. Немного странно? Но причина довольно тривиальна - отношения один к одному, которые сводят на нет первый объект, когда я устанавливаю его во втором.

Итак, схема такая:

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

Изменение отношения в Parent от одного к одному ко многим к одному решило эту задачу.

HotJard
источник
0

У меня было временное свойство типа int, которое не было обязательным. Очевидно, что при значении 0 появляется ошибка 1570. Просто изменил все мои переходные свойства на необязательные. При необходимости логика нулевой проверки может быть реализована в коде.

Антон Плебанович
источник
0

Я имею в виду, что ваша модель не прошла проверку, что могло произойти по ряду причин: неиспользуемое свойство в вашей модели, пропущенное значение, помеченное как необходимое. Чтобы лучше понять, что именно пошло не так, поместите точку останова в место, где вы готовы сохранить свой объект, и вызовите один из validateFor...вариантов метода, например:

po [myObject validateForInsert]

Более подробная информация о проблеме находится в описании ошибки. Успешная проверка означает, что вы не получите никаких результатов.

kkodev
источник
0

Это помогло мне. Проверьте это тоже.

Проверьте дополнительный ящик в вашем * объектах .xcodatamodel

ssowri1
источник