我一直在与CoreData有一段奇怪的问题。这将是一个长长的问题,所以请耐心等待......
我有两个Entites,称他们为A和B.B可能是几个A的创建者和更新者。 A必须有B作为创建者,并且可能有也可能没有B作为更新者。 (必需和可选关系。)
B可能同时创建和更新零个或多个A.
以上是我建立的数据模型。 (我真的不需要从B到A的反向关系,但是CoreData给了我编译时警告。)
修改
以下是ManagedObject子类的相关部分:
A.H
@property (nonatomic, retain) B * creator;
@property (nonatomic, retain) B * updater;
A.M
@dynamic creator;
@dynamic updater;
B.h
@property (nonatomic, retain) NSSet * created;
@property (nonatomic, retain) NSSet * updated;
B.m
@dynamic updated;
@dynamic created;
- (void)addUpdatedObject:(A *)value { NSSet *changedObjects = [[NSSet
alloc] initWithObjects:&value count:1]; [self
willChangeValueForKey:@"updated"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:changedObjects]; [[self
primitiveValueForKey:@"updated"] addObject:value]; [self
didChangeValueForKey:@"updated"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:changedObjects]; [changedObjects release]; }
- (void)removeUpdatedObject:(A *)value { NSSet *changedObjects =
[[NSSet alloc] initWithObjects:&value count:1]; [self
willChangeValueForKey:@"updated"
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:changedObjects]; [[self
primitiveValueForKey:@"updated"] removeObject:value]; [self
didChangeValueForKey:@"updated"
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:changedObjects]; [changedObjects release]; }
- (void)addUpdated:(NSSet *)value { [self
willChangeValueForKey:@"updated"
withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
[[self primitiveValueForKey:@"updated"] unionSet:value]; [self
didChangeValueForKey:@"updated"
withSetMutation:NSKeyValueUnionSetMutation usingObjects:value]; }
- (void)removeUpdated:(NSSet *)value { [self
willChangeValueForKey:@"updated"
withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
[[self primitiveValueForKey:@"updated"] minusSet:value]; [self
didChangeValueForKey:@"updated"
withSetMutation:NSKeyValueMinusSetMutation usingObjects:value]; }
- (void)addCreatedObject:(A *)value { NSSet *changedObjects = [[NSSet
alloc] initWithObjects:&value count:1]; [self
willChangeValueForKey:@"created"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:changedObjects]; [[self
primitiveValueForKey:@"created"] addObject:value]; [self
didChangeValueForKey:@"created"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:changedObjects]; [changedObjects release]; }
- (void)removeCreatedObject:(A *)value { NSSet *changedObjects =
[[NSSet alloc] initWithObjects:&value count:1]; [self
willChangeValueForKey:@"created"
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:changedObjects]; [[self
primitiveValueForKey:@"created"] removeObject:value]; [self
didChangeValueForKey:@"created"
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:changedObjects]; [changedObjects release]; }
- (void)addCreated:(NSSet *)value { [self
willChangeValueForKey:@"created"
withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
[[self primitiveValueForKey:@"created"] unionSet:value]; [self
didChangeValueForKey:@"created"
withSetMutation:NSKeyValueUnionSetMutation usingObjects:value]; }
- (void)removeCreated:(NSSet *)value { [self
willChangeValueForKey:@"created"
withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
[[self primitiveValueForKey:@"created"] minusSet:value]; [self
didChangeValueForKey:@"created"
withSetMutation:NSKeyValueMinusSetMutation usingObjects:value]; }
结束编辑
当我创建一个以B为创建者的新A时,一切都很好(使用反向关系时)。但是,当我稍后更新相同的A,使用与创建者相同的B时,我得到以下崩溃:
2011-05-05 13:17:40.885 myapp[27033:207] -[NSCFNumber count]:
unrecognized selector sent to instance 0x5d14eb0
2011-05-05 13:17:40.887 myapp[27033:207] *** Terminating app due to
uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFNumber
count]: unrecognized selector sent to instance
0x5d14eb0'
*** Call stack at first throw: (
0 CoreFoundation 0x014065a9
__exceptionPreprocess + 185
1 libobjc.A.dylib 0x0155a313 objc_exception_throw + 44
2 CoreFoundation 0x014080bb -[NSObject(NSObject)
doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x01377966 ___forwarding___ + 966
4 CoreFoundation 0x01377522 _CF_forwarding_prep_0 + 50
5 CoreFoundation 0x013b7c3b -[NSSet intersectsSet:] + 59
6 Foundation 0x00c3f4fb NSKeyValueWillChangeBySetMutation +
422
7 Foundation 0x00c0416d NSKeyValueWillChange + 400
8 Foundation 0x00c3f34d
-[NSObject(NSKeyValueObserverNotification)
willChangeValueForKey:withSetMutation:usingObjects:] + 315
9 CoreData 0x01172bd0 -[NSManagedObject
willChangeValueForKey:withSetMutation:usingObjects:] + 112
10 myapp 0x0004fd48 -[B addUpdatedObject:] + 168
11 CoreData 0x011729f2 -[NSManagedObject(_NSInternalMethods)
_includeObject:intoPropertyWithKey:andIndex:] + 98
12 CoreData 0x01169301 -[NSManagedObject(_NSInternalMethods)
_didChangeValue:forRelationship:named:withInverse:] + 497
13 Foundation 0x00c051e4 NSKeyValueNotifyObserver + 361
14 Foundation 0x00c04ca6 NSKeyValueDidChange + 384
15 Foundation 0x00beb3e2
-[NSObject(NSKeyValueObserverNotification)
didChangeValueForKey:] + 123
16 CoreData 0x01166adb
_PF_ManagedObject_DidChangeValueForKeyIndex + 171
17 CoreData 0x01165de9 _sharedIMPL_setvfk_core + 313
18 CoreData 0x01173997 _svfk_11 + 39
(是的, B 定义了addUpdatedObject
方法。)
有关更多背景信息,A:列表显示在由UITableView
支持的NSFetchedResultsController
中。
最奇怪的是,恕我直言,完全有可能添加一个新的A(以B作为创建者)与反向关系而不会导致崩溃,同时将相同的B作为更新者添加到同一个A导致崩溃。
但是,当我删除反向关系时,一切都按预期工作。
我可以添加与A:s创建者和更新程序相同的B而没有任何问题,应用程序可以正常工作,除了CoreData的构建时警告:
A.creator should have an inverse
A.updater should have an inverse
那么,是否有任何CoreData专家可以解释为什么第一个案例会破裂?
答案 0 :(得分:4)
你不应该能够建立双重关系。 Xcode 3.x和更早版本甚至不允许您创建具有双重关系的模型(现在只需检查Xcode 4,看起来它会让您在没有警告的情况下这样做。不是一个好主意。)
强烈建议不要使用双重关系,因为它们会严重影响图表的完整性,例如:删除规则,如果某个关系中的delete
规则和另一个关系中的deny
规则会发生什么?我认为双重关系的图表只是等待发生的火车残骸。
更重要的是,我从未看到真正需要这种数据模型的情况。通常,更好的数据模型设计将消除对这种危险设置的明显需求。在这种情况下,我认为您需要插入实体来模拟实际关系本身,因为关系实际上有行为或排序:
A{
creator<-->Creation.a
updater<-->Update.a
}
B{
creations<-->>Creation.b
updates<-->>Update.b
}
Creation{
a<-->A.creator
b<-->>B.cretions
}
Update{
a<-->A.updater
b<<-->B.updates
}
这样,您只需向Update
实体添加属性,即可轻松对更新日期等内容进行建模。
答案 1 :(得分:0)
更改模型后,是否为两个实体再次创建了ManagedObject子类(通过添加反转)?
如果不这样做,模型可能会尝试向不准备接受它们的对象添加反向引用。