错误而用于添加场景的视图控制器的dealloc的NSManagedObjectContext,但确定为编辑场景

问题描述:

我已经两个控制器,一个被NSFetchedResultsController错误而用于添加场景的视图控制器的dealloc的NSManagedObjectContext,但确定为编辑场景

@interface AddressesController : UITableViewController<ManageAddressDelegate> 
@property(nonatomic, strong) NSFetchedResultsController *fetchedResultsController; 
@end 

哪个显示地址通常称作AddressesController,并执行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命名为编辑上下文中AddressesController#prepareForSegue的地址准备子控制器SEGUE:发件人 (设置代表协议也)

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确定后将其保存到CoreData中。 我使用魔法记录来执行CoreData相关操作 和上述代码[address.managedObjectContext saveToPersistentStoreAndWait];”意愿引起默认上下文中也被保存 和我曾尝试使用正常[的NSManagedObjectContext:保存:错误]中,错误是一样的

问题是,虽然添加和编辑逻辑是相同的99%,但它可以编辑。 当我添加一个地址,它将被保存到数据库,并引发一个异常当[self。navigationController popViewControllerAnimated:YES]被调用时,发生错误时EditAddressController的dealloc所述的ivar 上下文

EXC_BAD_ACCESS(代码= 2,地址= 0x3)

错误堆栈带有(列出一些关键功能只):

[NSPersistStoreCache decrementRefCountForObjectID] 
... 
[NSManagedObjectContext(_NestedContextSupport) managedContextDidUnregisterObjectsWithIDs:] 
... 
[NSManagedObjectContext dealloc] 
+0

经过一些测试后,我发现两个案例之间最重要的区别是地址对象,新地址相关联的上下文似乎已经'绑定'并拒绝任何'release/dealloc'尝试。 – Kadvin 2013-04-23 06:11:02

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

我们应该低于消息后发送一个复位消息给管理对象上下文:

[address.managedObjectContext saveToPersistentStoreAndWait]; 

[address.managedObjectContext reset]; 

而且我不知道为什么编辑对象不会造成错误的想法。