关系保存时核心数据崩溃

Posted

技术标签:

【中文标题】关系保存时核心数据崩溃【英文标题】:Core Data crash on relationship save 【发布时间】:2014-08-06 20:10:02 【问题描述】:

我有一个核心数据应用程序,我正在尝试将新对象添加到具有关系的实体中。访问导致应用在保存

时崩溃的关系实体出现问题

添加发生在工作表中。

保存动作:

-(IBAction)addNewRepair:(id)sender 
    NSError *error = nil;
    NSArray *fetchedObjects;
    NSManagedObjectContext *context = [[NSApp delegate] managedObjectContext];

    NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Equipment"  inManagedObjectContext:context];

    [fetch setEntity:entityDescription];

    [fetch setPredicate:[NSPredicate predicateWithFormat:@"(serial like %@)",[[serialPopUp selectedItem] title]]];

    fetchedObjects = [context executeFetchRequest:fetch error:&error];

    Equipment *equipmentObject = [fetchedObjects objectAtIndex:0];

    Repairs *newRepair = (Repairs*)[NSEntityDescription
                                    insertNewObjectForEntityForName:@"Repairs"
                                    inManagedObjectContext:[[NSApp delegate] managedObjectContext]];

    [newRepair setValue:invoiceNumberTextFeild.stringValue forKeyPath:@"invoiceNumber"];
    [newRepair setValue:warrentyTextField.stringValue forKeyPath:@"warrantyDate"];
    [newRepair setValue:repairReasonTextField.stringValue forKeyPath:@"repairDetails"];
    [newRepair setValue:serviceProvidedTextField.stringValue forKeyPath:@"serviceSummary"];
    [newRepair setValue:serviceDateTextField.stringValue forKeyPath:@"repairDate"];
    [equipmentObject addRepairsObject:(Repairs *)newRepair];

    if (![[[NSApp delegate] managedObjectContext]  save:&error])
    
        NSLog(@"couldn't save: %@", [error localizedDescription]);
    

    NSLog((@"Repair Successfully added"));
    [NSApp endSheet:self.sheet];
    [self.sheet close];

获取方法:

-(void)fetchItems 

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Equipment"];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Equipment" inManagedObjectContext:[[NSApp delegate] managedObjectContext]];

    fetchRequest.propertiesToFetch = [NSArray arrayWithObject:[[entity propertiesByName] objectForKey:@"item"]];

    fetchRequest.entity = entity;
    fetchRequest.resultType = NSDictionaryResultType;
    [fetchRequest setReturnsDistinctResults:YES];

    itemDictionaries = [[[NSApp delegate] managedObjectContext] executeFetchRequest:fetchRequest error:nil];

    NSLog(@"item: %@", itemDictionaries);

    [nameController setContent:itemDictionaries];
    self.itemSelection = [itemDictionaries firstObject];

    self.predicate  = [NSPredicate predicateWithFormat:@"item == %@", [[nameController selection] valueForKeyPath:@"item"]];

这种方法可能出了什么问题?

我的设备.h 文件实现了一个自定义访问器:

- (void)addRepairsObject:(Repairs *)value;

    [self willChangeValueForKey:@"Repairs"];
    [self setPrimitiveValue:value forKey: @"Repairs"];
    [self didChangeValueForKey:@"Repairs"];

我得到的错误是:

2014-08-06 12:41:50.805 CNSplitView_Example[64803:4407] -[设备 copyWithZone:]: 无法识别的选择器发送到实例 0x6080002c0a10

即使equipment.h' listsrepairs` 为

@property (nonatomic, retain) NSSet *repairs;

有人能指出我正确的方向吗?从我正在阅读的内容来看,这是一个常见问题(几乎总是在 ios 上,而不是 OS X 应用程序上),但没有广泛记录的解决方案。

我也试过这个:

NSMutableSet *newRepairObject = [NSMutableSet setWithObject:equipmentObject];
    equipmentObject.repairs = newRepairObject;

同样的错误。

编辑:

发现NSManagedObjects 不符合NSCopying 协议。 (那么为什么在该实体上生成 copyWithZone 时出错?)

【问题讨论】:

Equipment类是否采用NSCopying协议?该错误消息向我表明该应用程序期望它。 如果我尝试实现 nscopying,我仍然会收到相同的错误:“无法识别的选择器发送到实例 0x6000002bb660 with userInfo (null)” 另外,根据我的阅读,NSManagedObjects 不符合 NSCopying anyuway 【参考方案1】:

问题在于 addRepairsObject: 方法。您正在使用属性访问器 setPrimitiveValue: 当您应该使用一对多关系访问器时。核心数据编程指南在Managed Object Accessor Methods部分给出了一个例子

@dynamic employees;


- (void)addEmployeesObject:(Employee *)value 

    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];

    [self willChangeValueForKey:@"employees"
          withSetMutation:NSKeyValueUnionSetMutation
          usingObjects:changedObjects];
    [[self primitiveEmployees] addObject:value];
    [self didChangeValueForKey:@"employees"
          withSetMutation:NSKeyValueUnionSetMutation
          usingObjects:changedObjects];

用“repairs”代替“employees”,应该没问题。 NSCopying 错误是红鲱鱼:在 Core Data 中,很多事情都发生在水下,那里的崩溃可能会使一些奇怪的碎片向上漂浮,从而掩盖真正的问题。

【讨论】:

以上是关于关系保存时核心数据崩溃的主要内容,如果未能解决你的问题,请参考以下文章

崩溃前保存核心数据上下文

从后台线程保存数据时核心数据崩溃

核心数据 VS 验证错误对象,导致崩溃

核心数据和多线程在保存时崩溃

尝试从响应 Swift Alamofire 将数据保存到核心数据时崩溃

仅针对临时构建和旧设备保存时核心数据崩溃