私は2つのコントローラーを持っています.1つはAddressesControllerと呼ばれます
@interface AddressesController : UITableViewController<ManageAddressDelegate>
@property(nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
@end
通常、NSFetchedResultsController によってアドレスを表示し、次のようなユーザー アクションに対して SegueAddAddress を実行します。
- (IBAction)addButtonClicked:(id)sender {
[self performSegueWithIdentifier:SegueNewAddress sender:sender];
}
行をクリックすると SegueEditAddress が実行されます。
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
Address *address = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self performSegueWithIdentifier:SegueEditAddress sender:address];
}
別のコントローラーは EditAddressController で、SegueAddAddress と SegueEditAddress の両方の destinationViewController です。
@interface EditAddressController : UITableViewController<EZFormDelegate>
@property (strong, nonatomic) Address *address;
@property (strong, nonatomic) NSManagedObjectContext *context;
@property (weak, nonatomic) id <ManageAddressDelegate> delegate;
@end
AddressesController#prepareForSegue:sender で editContext という名前のサブ NSManagedObjectContext のアドレスを使用して、サブコントローラーのセグエを準備します (デリゲートプロトコルもセットアップします)。
if ([segue.identifier isEqualToString:SegueEditAddress]) {
EditAddressController *controller = segue.destinationViewController;
controller.delegate = self;
NSManagedObjectContext *editContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
editContext.MR_workingName = @"Edit Address Context";
[editContext setParentContext:[self.fetchedResultsController managedObjectContext]];
Address *address = sender;
Address *editAddress = [address inContext:editContext];
controller.address = editAddress;
controller.context = editContext;
}
追加するために、addingContext で新しいアドレスを準備します。
if ([segue.identifier isEqualToString:SegueNewAddress]) {
EditAddressController *controller = segue.destinationViewController;
controller.delegate = self;
NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
addingContext.MR_workingName = @"Adding Address Context";
[addingContext setParentContext:[self.fetchedResultsController managedObjectContext]];
Address *newAddress = [Address createInContext:addingContext];
controller.address = newAddress;
controller.context = addingContext;
}
ユーザーが EditAddressController の保存ボタンをクリックすると、アドレス プロパティを入力した後、以下のコードでデリゲート (AddressesController) がコールバックされます。
- (IBAction)save:(id)sender {
[self.delegate controller:self save:self.address];
}
また、元の AddressesController は、同じコールバック関数によって新しいアクションまたは編集アクションを処理します。
- (void)controller:(EditAddressController *)controller save:(Address *)address {
NSArray *keys = @[@"username", @"phone", @"zipcode", @"street"];
NSDictionary *attributes = [address dictionaryWithValuesForKeys:keys];
void (^success)(AFHTTPRequestOperation *, id) = ^(AFHTTPRequestOperation *operation, id responseObject) {
[address importValuesForKeysWithObject:[responseObject JSONValue]];
[address.managedObjectContext saveToPersistentStoreAndWait];
[self.navigationController popViewControllerAnimated:YES];
};
void (^failure)(AFHTTPRequestOperation *, NSError *) = ^(AFHTTPRequestOperation *operation, NSError *error) {
DDLogError(@"Failed to create address because of: %@", error);
};
if (address.id == nil || address.id.intValue == 0) {
[self.http postPath:@"addresses" parameters:parameters success:success failure:failure];
} else {
NSString *path = [NSString stringWithFormat:@"addresses/%@", address.id];
[self.http putPath:path parameters:parameters success:success failure:failure];
}
}
この関数は、新しいアドレスまたは編集したアドレスをサーバーに投稿し、http OK の後に CoreData に保存するだけです。私は Magical Record を使用して CoreData 関連の操作を実行し、上記のコード[address.managedObjectContext saveToPersistentStoreAndWait];"により、デフォルトのコンテキストも保存されます。通常の [NSManagedObjectContext:save:error] を使用しようとしましたが、エラーは同じです。
問題は、追加と編集のロジックは 99% 同じですが、編集には問題ありません。アドレスを追加すると、それは db に保存され、[self.navigationController popViewControllerAnimated:YES]が呼び出されると例外が発生し、EditAddressController が ivarコンテキストを解放するときにエラーが発生しました:
EXC_BAD_ACCESS (コード=2、アドレス=0x3)
エラースタックが付属しています(いくつかの主要な機能のみをリストしてください):
[NSPersistStoreCache decrementRefCountForObjectID]
...
[NSManagedObjectContext(_NestedContextSupport) managedContextDidUnregisterObjectsWithIDs:]
...
[NSManagedObjectContext dealloc]