保存しようとするとコアデータから奇妙なエラーメッセージが表示されますが、エラーが再現できないという問題があります(異なるタスクを実行すると異なる時間に表示されます)
エラーメッセージ:
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
}
}
このメッセージの理由は何ですか?ランダムに出現することを与える
必須プロパティにnilが割り当てられていることを意味します。 * .xcodatamodelで[オプション]ボックスをチェックするか、managedObjectContextに保存するときに、プロパティが入力されていることを確認してください。
2つの要件に合わせてコードを変更した後にさらにエラーが発生する場合は、ビルドをクリーンアップして、iPhone Simulator/iPhoneデバイスからアプリケーションを削除してください。モデルの変更は、古いモデルの実装と競合する場合があります。
編集:
Core Dataが吐き出すすべてのエラーコードがここにあるのをほとんど忘れていました: Core Data Constants Reference これで問題があり、正しいオプションボックスのチェックを外したことに気付きました。問題を見つけるそのようなトラブル。幸運を。
私はこれに少し苦労しました。ここでの本当の問題は、あなたが持っているデバッグが問題が何であるかをあなたに示していないということです。これは、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]);
}
}
不足しているフィールドを示す出力が生成されるため、問題の修正が非常に簡単になります。
これはチャールズのスニペットの装飾のようなものですが、これを答えとして投げ込んでいます。 NSLogからのまっすぐな出力は、読み取りと解釈が面倒になる可能性があるため、空白をいくつか挿入して、重要な「userInfo」キーの値を呼び出すのが好きです。
ここに私が使ってきた方法のバージョンがあります。 (「_sharedManagedObjectContext」は、「[[[UIApplication sharedApplication] delegate] managedObjectContext]」の#defineです。)
- (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から問題が発生したときに、保存する前に設定するのを忘れていた非オプションのコアデータエンティティを直接指し示していました。
助けてくれました。これもチェックしてください。
* .xcodatamodelオブジェクトのオプションボックスをチェックします
オプションではないint型の一時的なプロパティがありました。明らかに、0に設定された場合、1570エラーが表示されます。すべての一時的なプロパティをオプションに変更しました。必要に応じて、コードにゼロチェックロジックを実装できます。
モデルの検証に失敗したことを意味します。これはいくつかの理由で発生する可能性があります。モデルの未使用のプロパティ、必要とマークされた値の欠落。正確に何が間違っていたのかをよりよく理解するには、オブジェクトを保存する準備ができている場所にブレークポイントを置き、次のようなvalidateFor...
メソッドバリアントのいずれかを呼び出します。
po [myObject validateForInsert]
問題に関するより詳細な情報は、エラーの説明にあります。検証が成功すると、出力が得られなくなります。
2番目のレコードをCoreDataに保存すると、問題に感動しました。オプションではないフィールド(関係)もすべてnilなしで埋められましたが、エラー出力では、最初に保存されたオブジェクトのフィールドの1つがnilになったことがわかります。ちょっと変なの?しかし、その理由は非常に簡単です。2番目に設定したときに、最初のオブジェクトを無効にする1対1の関係です。
したがって、スキームは次のとおりです。
"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)
親の関係を1対1から多対1に変更することで、このタスクを解決しました。