使用生成的访问器删除对象时,iOS Core Data to-many关系中断

时间:2011-08-16 15:32:39

标签: ios cocoa-touch core-data

我有一个iOS 4 +应用程序,现在正在改装以使用Core Data。我有一个实体“文章”,它与另一个实体“MediaResource”有很多关系,我为每个实体生成了NSManagedObject子类。该关系称为“media”并设置为可选,并且Cascade删除关联的MediaResource对象。该条款有一个反向的反对。

生成的代码包含Article类中NSSet * media类型的属性,以及这些方法:

- (void)addMediaObject:(MediaResource *)value {    
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"media" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [[self primitiveValueForKey:@"media"] addObject:value];
    [self didChangeValueForKey:@"media" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [changedObjects release];
}

- (void)removeMediaObject:(MediaResource *)value {
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"media" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [[self primitiveValueForKey:@"media"] removeObject:value];
    [self didChangeValueForKey:@"media" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [changedObjects release];
}

- (void)addMedia:(NSSet *)value {    
    [self willChangeValueForKey:@"media" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
    [[self primitiveValueForKey:@"media"] unionSet:value];
    [self didChangeValueForKey:@"media" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
}

- (void)removeMedia:(NSSet *)value {
    [self willChangeValueForKey:@"media" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
    [[self primitiveValueForKey:@"media"] minusSet:value];
    [self didChangeValueForKey:@"media" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
}

这里没有NSMutableSets,但我认为自动生成的代码知道它在做什么。

我可以添加一篇文章,然后添加一个MediaResource对象,并按照以下方式执行:

            [newArticle addMediaObject:newMediaObject];

我从文档中收集到正确的方法。但是,我也看到了使用mutableSetValueForKey:的参考,但这似乎不适用于此。

基本上,会发生的是,在给定的运行期间,我可以添加一篇文章,然后将其删除,并且它可以正常工作。但是,如果我然后添加它,退出应用程序然后重新运行它,然后删除它,我得到一个异常,它告诉NSSet删除一个对象,当然这是不能做的。由于我实际上没有写这些方法,我很困惑。有任何想法吗?这是相关的堆栈跟踪:

2011-08-16 11:12:32.141 MyApp[41825:207] -[__NSSet0 removeObject:]: unrecognized selector sent to instance 0x8041f60
2011-08-16 11:12:32.144 MyApp[41825:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSet0 removeObject:]: unrecognized selector sent to instance 0x8041f60'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x01a5b5a9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x01baf313 objc_exception_throw + 44
    2   CoreFoundation                      0x01a5d0bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
    3   CoreFoundation                      0x019cc966 ___forwarding___ + 966
    4   CoreFoundation                      0x019cc522 _CF_forwarding_prep_0 + 50
    5   CTKennedy                           0x000b292c -[Article removeMediaObject:] + 220
    6   CoreData                            0x0054a1f2 -[NSManagedObject(_NSInternalMethods) _excludeObject:fromPropertyWithKey:andIndex:] + 98
    7   CoreData                            0x0053f7d1 -[NSManagedObject(_NSInternalMethods) _maintainInverseRelationship:forProperty:oldDestination:newDestination:] + 449
    8   CoreData                            0x00593b55 -[NSManagedObject(_NSInternalMethods) _propagateDelete:] + 1541
    9   CoreData                            0x0054a02a -[NSManagedObject(_NSInternalMethods) _propagateDelete] + 42
    10  CoreData                            0x00549e53 -[NSManagedObjectContext(_NSInternalChangeProcessing) _propagateDeletesUsingTable:] + 515
    11  CoreData                            0x00549c12 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processDeletedObjects:] + 146
    12  CoreData                            0x0053cba8 -[NSManagedObjectContext(_NSInternalChangeProcessing) _propagatePendingDeletesAtEndOfEvent:] + 104
    13  CoreData                            0x00508982 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 754
    14  CoreData                            0x00542715 -[NSManagedObjectContext save:] + 149

1 个答案:

答案 0 :(得分:3)

您的问题不是由自动生成的代码引起的。您没有看到可变集,因为Core Data实际上为NSSet使用了类集群,并在访问了多对多关系时返回了anther类_NSFaultingMutableSet。 NSSet很可能在头文件中使用,以防止其他类在不使用已定义的方法的情况下尝试设置关系。

我有一个生成的类Alpha设置,其中包含与betas类的多对多关系Beta。如果我在这个方法的第一行放置一个断点:

-(void)addBetasObject:(NSManagedObject *)value {    
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"betas" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [[self primitiveValueForKey:@"betas"] addObject:value];
    [self didChangeValueForKey:@"betas" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [changedObjects release];
}

...我可以在调试器提示符下执行此操作:

(gdb) po [self primitiveValueForKey:@"betas"]
Relationship objects for {(
)} on 0x4d45e20
(gdb) po [[self primitiveValueForKey:@"betas"] class]
_NSFaultingMutableSet

因此,尽管有标题,但该属性是一个可变集,尽管是自定义集。

同样,使用匹配方法:

- (void)removeBetasObject:(NSManagedObject *)value {
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"betas" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [[self primitiveValueForKey:@"betas"] removeObject:value];
    [self didChangeValueForKey:@"betas" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [changedObjects release];
}

...保存后,调试器给出:

(gdb) po [self primitiveValueForKey:@"betas"]
Relationship objects for {(
    <Beta: 0x4d4be40> (entity: Beta; id: 0x4d52510 <x-coredata://64E86DEC-53DA-4197-B1F3-6C0007576100/Beta/p1> ; data: {
    alphas =     (
        "0x4d52140 <x-coredata://64E86DEC-53DA-4197-B1F3-6C0007576100/Alpha/p1>"
    );
    num = 0;
})
)} on 0x4d45e20
(gdb) po [[self primitiveValueForKey:@"betas"] class]
_NSFaultingMutableSet

这种幕后变化是因为@dynamic betas的{​​{1}}处理器指令,即@dynamic betas;,如果该行被删除,那么属性将完全按原样定义在标题中。

检查Article.m @dynamic media;文件中的@synthesize media;如果文件丢失或{{1}}是您问题的根源。