我目前正在研究核心数据和新手,从地址簿中获取复合名称和联系电话。我现在可以使用 KVC 和子类化 NSManagedObject 以一对一和对多关系保存数据。但是还有一些概念我不太清楚。
在普通的数据库中,我们以主键和外键的方式保存数据。 ContactName 表中的 ID、compositeName 字段和 ContactNumber 表中的 ID、number、type 字段。可以在两个表 ID 字段上轻松创建关系。
在核心数据中,它是这样使用 KVC 完成的:
1. NSManagedObject *contactNameEntity = [NSEntityDescription insertNewObjectForEntityForName:@"ContactName" inManagedObjectContext:self.managedObjectContext];
2. [contactNameEntity setValue:@"TheName" forKey:@"compositeName"]
3. NSMutableSet *relationAsSet = [contactNameEntity mutableSetValueForKey:@"contactNameRelation"];
//fetching multi values like contact mobile, iPhone, home, work, other numbers and iterating them
4. ABMutableMultiValueRef multiValues = ABRecordCopyValue(ref, kABPersonPhoneProperty);
5. CFArrayRef mVArray = ABMultiValueCopyArrayOfAllValues(multiValues);
6. for(int i=0; i<CFArrayGetCount(mVArray); i++) {
7. NSManagedObject *contactNumberEntity = [NSEntityDescription insertNewObjectForEntityForName:@"ContactNumber" inManagedObjectContext:self.managedObjectContext];
8. [contactNumberEntity setValue:(__bridge NSString*)CFArrayGetValueAtIndex(mVArray, i) forKey:@"number"];
9. [contactNumberEntity setValue:(__bridge id)(ABMultiValueCopyLabelAtIndex(multiValues, i)) forKey:@"type"];
10. [relationAsSet addObject:contactNumberEntity];
}
11. [contactNameEntity setValue:relationAsSet forKey:@"contactNameRelation"];
现在使用实体子类方法#1:
1. ContactName *contactNameEntity = [NSEntityDescription insertNewObjectForEntityForName:@"ContactName" inManagedObjectContext:self.managedObjectContext];
2. [contactNameEntity setCompositeName:(__bridge id)(compositeName)];
3. for(int i=0; i<CFArrayGetCount(mVArray); i++) {
4. ContactNumber *contactNumberEntity = [NSEntityDescription
5. insertNewObjectForEntityForName:@"ContactNumber" inManagedObjectContext:self.managedObjectContext];
6. [contactNumberEntity setNumber:(__bridge NSString*)CFArrayGetValueAtIndex(mVArray, i)];
7. [contactNumberEntity setType:(__bridge id)(ABMultiValueCopyLabelAtIndex(multiValues, i))];
8. [contactNameEntity addContactNameRelationObject:contactNumberEntity];
}
现在有了类似于 KVC 方法 #2 的实体子类:
1. ContactName *contactNameEntity = [NSEntityDescription insertNewObjectForEntityForName:@"ContactName" inManagedObjectContext:self.managedObjectContext];
2. [contactNameEntity setCompositeName:(__bridge id)(compositeName)];
3. NSSet *set = [contactNameEntity contactNameRelation];
4. NSMutableSet *mSet = [NSMutableSet setWithSet:set];
5. set = nil;
6. for(int i=0; i<CFArrayGetCount(mVArray); i++) {
7. ContactNumber *contactNumberEntity = [NSEntityDescription
8. insertNewObjectForEntityForName:@"ContactNumber" inManagedObjectContext:self.managedObjectContext];
9. [contactNumberEntity setNumber:(__bridge NSString*)CFArrayGetValueAtIndex(mVArray, i)];
10. [contactNumberEntity setType:(__bridge id)(ABMultiValueCopyLabelAtIndex(multiValues, i))];
11. [mSet addObject:contactNumberEntity];
}
12. [contactNameEntity addContactNameRelation:mSet];
问题:
KVC方法第3行,为什么无法创建普通的NSSet?
为什么关系以 NSSet 的形式存在,虽然在正常的 DB 关系中只是一件简单的事情,但在核心数据中似乎很复杂。
我是否正确使用了子类生成的方法,或者我是否以标准方式使用了子类生成的方法? (要求验证我的概念)。
为什么方法 #1 和方法 #2 不同?两者都在使用子类。
@property (nonatomic, retain) NSSet *contactNameRelation;
和NSMutableSet *relationAsSet = [contactNameEntity mutableSetValueForKey:@"contactNameRelation"];
返回相同的对象/值?
*。请避免任何愚蠢的错误。
*。请告诉我我问的问题不清楚。
编辑 1
ContactName实体xcode生成的子类.h文件:
@property (nonatomic, retain) NSString * number;
@property (nonatomic, retain) NSSet *contactNumbers;
@end
@interface ContactName (CoreDataGeneratedAccessors)
- (void)addContactNumbersObject:(ContactNumber *)value;
- (void)removeContactNumbersObject:(ContactNumber *)value;
- (void)addContactNumbers:(NSSet *)values;
- (void)removeContactNumbers:(NSSet *)values;
这是 .m 文件:
@implementation ContactName
@dynamic compositeName;
@dynamic contactNumbers;
@end
我想知道如何正确使用这些方法,这就是为什么方法 1 和方法 2 是我上面基于此子类发布的两种不同方法的原因。什么是正确的,什么是不正确的,请帮助我。
编辑2
这是我在记录 relationAsSet 时得到的结果
$0 = 0x0854c1c0 Relationship 'contactNameRelation' on managed object (0x835bae0) <ContactName: 0x835bae0> (entity: ContactName; id: 0x835ba80 <x-coredata:///ContactName/t66752D00-F08B-40DF-AEED-ABCACEA254652> ; data: {
compositeName = myname;
contactNameRelation = (
);
}) with objects {(
)}
还有这个
$0 = 0x0821b460 Relationship 'contactNameRelation' on managed object (0x823fe50) <ContactName: 0x823fe50> (entity: ContactName; id: 0x823fea0 <x-coredata:///ContactName/t3CED08C3-94E0-4B43-93F0-96DE2D2A24922> ; data: {
compositeName = myname;
contactNameRelation = (
"0x821be40 <x-coredata:///ContactNumber/t3CED08C3-94E0-4B43-93F0-96DE2D2A24923>"
);
}) with objects {(
<ContactNumber: 0x8241ab0> (entity: ContactNumber; id: 0x821be40 <x-coredata:///ContactNumber/t3CED08C3-94E0-4B43-93F0-96DE2D2A24923> ; data: {
contactNumberRelation = "0x823fea0 <x-coredata:///ContactName/t3CED08C3-94E0-4B43-93F0-96DE2D2A24922>";
number = 123;
type = iphone;
})
)}
最佳答案
正如@svena 已经说过的,您的关系名称有点“非常规”(而且您似乎已经在添加的代码中部分更改了它们)。所以我将采用以下模型和关系名称:
一对多关系的值是一个NSSet
。例如
ContactName *aContact = ...;
NSSet *relatedNumbers = aContact.contactNumbers;
// or equivalently, using KVC:
relatedNumbers = [aContact valueForKey:@"contactNumbers"];
for (ContactNumber *contactNumber in relatedNumbers) {
NSLog(@"%@", contactNumber.number);
}
因此您使用关系的值(在本例中为 NSSet
)来遍历对象
图并找到相关对象。但是你不能修改这个集合(它是不可变的)。
然后你有关于
的问题NSMutableSet *mutableRelatedNumbers = [aContact mutableSetValueForKey:@"contactNumbers"];
这是一件很特别的事情。它是一个可变集,“绑定(bind)”到 aContact
对象。这意味着如果你修改这个集合(添加或删除一些东西)然后你有效地修改
aContact
对象的 contactNumbers
关系。
所以
ContactName *aContact = ...;
ContactNumber *aContactNumber1 = ...;
ContactNumber *aContactNumber2 = ...;
// (A)
NSMutableSet *mutableRelatedNumbers = [aContact mutableSetValueForKey:@"contactNumbers"];
[mutableRelatedNumbers addObject:aContactNumber1];
[mutableRelatedNumbers addObject:aContactNumber2];
(这是您的第一个代码块的更正版本)是执行此操作的复杂方法
// (B)
[aContact addContactNumbersObject:aContactNumber1];
[aContact addContactNumbersObject:aContactNumber2];
(这是您的方法#1)。另一种等价的方法是(因为反比关系)
// (C)
aContactNumber1.contactName = aContact;
aContactNumber2.contactName = aContact;
或
// (D)
NSMutableSet *mset = [NSMutableSet set];
[mset addObject:aContactNumber1];
[mset addObject:aContactNumber2];
[aContact addContactNumbers:mset];
类似于 (B),是您的方法 #2 的更正版本。
这些都是将对象添加到关系中的有效方法,但 (C) 最容易使用,其次是 (B)。 (A) 和 (D) 很少使用。 (C) 的另一个优点是更好的类型检查。
所以即使我没有直接回答问题,我也希望这有助于澄清问题!
关于ios - 需要有关核心数据关系概念的帮助,不要求任何代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15810203/