0

我有两个控制器,一个称为 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]
4

1 回答 1

0

经过几轮测试,我找到了根本原因:

我们应该在以下消息之后向托管对象上下文发送重置消息:

[address.managedObjectContext saveToPersistentStoreAndWait];

[address.managedObjectContext reset];

而且我不知道为什么编辑对象不会导致错误。

于 2013-04-23T06:48:29.963 回答