我有两个控制器,一个称为 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
我将为子控制器准备 segue,在子 NSManagedObjectContext 中有一个地址,在 AddressesController#prepareForSegue:sender 中命名为editContext(也设置委托协议)
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%的添加和编辑逻辑是一样的,但是编辑没问题。当我添加一个地址时,它将被保存到数据库中,并在调用[self.navigationController popViewControllerAnimated:YES]时引发异常,当 EditAddressController 释放 ivar上下文时发生错误:
EXC_BAD_ACCESS(代码=2,地址=0x3)
错误堆栈附带(仅列出一些关键功能):
[NSPersistStoreCache decrementRefCountForObjectID]
...
[NSManagedObjectContext(_NestedContextSupport) managedContextDidUnregisterObjectsWithIDs:]
...
[NSManagedObjectContext dealloc]