我在弄清楚如何在NSTokenField中表示多对多关系模型时遇到了问题。我有两个(相关的)模型:
项目标签
一个项目可以有多个标签,一个标签可以有多个项目。所以这是一种反向的多对多关系。
我想要做的是在NSTokenField中表示这些标记。我希望最后有一个自动建议匹配的令牌域(找到了一种使用tokenfield:completionsForSubstring:indexOfToken:indexOfSelectedItem)实现这一点的方法,并能够在与现有标记实体不匹配的情况下添加新的标记实体。
好吧,希望你还在听我说。我正在尝试使用绑定和数组控制器来完成所有这些工作(因为这最有意义,对吧?)
我有一个数组控制器,“项目数组控制器”,绑定到我的应用程序委托managedObjectContext。显示所有项的表视图具有到此数组控制器的绑定。
我的NSTokenField的值绑定到数组控制器选择键和模型键path: tag。
使用此配置,NSTokenField将不会显示标记。它只是给了我:
<NSTokenFieldCell: 0x10014dc60>: Unknown object type assigned (Relationship objects for {(
<NSManagedObject: 0x10059bdc0> (entity: Tag; id: 0x10016d6e0 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Tag/p102> ; data: <fault>)
)} on 0x100169660). Ignoring...这对我来说是有意义的,所以不用担心。我已经研究了一些NSTokenField委托方法,似乎应该使用:
- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject问题是,这个方法没有被调用,我得到了和以前一样的错误。
好的,我的下一步就是尝试做一个ValueTransformer。从带有标记实体->数组和字符串(标记名)的数组进行转换是很好的。另一种方式更具挑战性。
我尝试的是在我的共享应用中查找每个名字,委托托管对象上下文,并返回匹配的标签。显然,这给我带来了不同托管对象上下文的问题:
Illegal attempt to establish a relationship 'tags' between objects in different contexts (source = <NSManagedObject: 0x100156900> (entity: Item; id: 0x1003b22b0 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Item/p106> ; data: {
author = "0x1003b1b30 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Author/p103>";
createdAt = nil;
filePath = nil;
tags = (
);
title = "Great presentation";
type = "0x1003b1150 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Type/p104>";
}) , destination = <NSManagedObject: 0x114d08100> (entity: Tag; id: 0x100146b40 <x-coredata://9D77D47A-1171-4397-9777-706F599D7E3B/Tag/p102> ; data: <fault>))我哪里错了?我该如何解决这个问题?这是正确的方法吗(在我看来,你必须使用ValueTransformer是很奇怪的?)
提前感谢!
发布于 2011-04-19 19:47:06
我已经编写了一个自定义NSValueTransformer来在绑定的NSManagedObject/Tag NSSet和token字段的NSString NSArray之间进行映射。以下是两种方法:
- (id)transformedValue:(id)value {
if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = (NSSet *)value;
NSMutableArray *ary = [NSMutableArray arrayWithCapacity:[set count]];
for (Tag *tag in [set allObjects]) {
[ary addObject:tag.name];
}
return ary;
}
return nil;
}
- (id)reverseTransformedValue:(id)value {
if ([value isKindOfClass:[NSArray class]]) {
NSArray *ary = (NSArray *)value;
// Check each NSString in the array representing a Tag name if a corresponding
// tag managed object already exists
NSMutableSet *tagSet = [NSMutableSet setWithCapacity:[ary count]];
for (NSString *tagName in ary) {
NSManagedObjectContext *context = [[NSApp delegate] managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *searchFilter = [NSPredicate predicateWithFormat:@"name = %@", tagName];
NSEntityDescription *entity = [NSEntityDescription entityForName:[Tag className] inManagedObjectContext:context];
[request setEntity:entity];
[request setPredicate:searchFilter];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
if ([results count] > 0) {
[tagSet addObjectsFromArray:results];
}
else {
Tag *tag = [[Tag alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
tag.name = tagName;
[tagSet addObject:tag];
[tag release];
}
}
return tagSet;
}
return nil;
}CoreData似乎会在返回时自动建立对象关系(但我还没有完全验证这一点)
希望能有所帮助。
发布于 2011-04-19 22:12:42
第二个错误是由于两个单独的托管对象上下文具有相同的模型和存储同时处于活动状态而导致的。您正尝试在一个上下文中创建一个对象,然后在第二个上下文中将其与另一个对象相关联。这是不允许的。你需要丢掉第二个上下文,把你所有的关系都放在一个上下文中。
您的初始错误是由不完整的keypath引起的。根据您的描述,您似乎正在尝试使用ItemsArrayController.selectedItem.tags填充token字段,但这只会返回一个token字段无法使用的Tag对象。相反,您需要为它提供一些可以转换为字符串的内容,例如ItemsArrayController.selectedItem.tags.name
发布于 2011-02-24 21:29:12
2个问题:
1)除了你的应用委托的上下文之外,你有没有正在使用的NSManagedObjectContext ? 2)实现tokenField:displayStringForRepresentedObject:的对象是否设置为NSTokenField的委托?
https://stackoverflow.com/questions/3880961
复制相似问题