我有两个控制器,一个叫做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
我将使用子NSManagedObjectContext中的地址为子控制器准备segue,该地址在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;
}
在addContext中准备一个新地址以便添加:
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]
答案 0 :(得分:0)
我们应该在以下消息之后向托管对象上下文发送重置消息:
[address.managedObjectContext saveToPersistentStoreAndWait];
[address.managedObjectContext reset];
我不知道为什么编辑对象不会导致错误。