Короче говоря, я хочу связать произвольные пары ключ / значение с объектами сущности Core Data в приложении для iPad.
Мое текущее решение состоит в том, чтобы иметь отношение ко многим с другой сущностью, котораяпредставляет одну пару.В моем приложении у меня есть:
Entry <--->> ExtraAttribute
, где ExtraAttribute
имеет свойства key
и value
, а key
уникален для записи ExtraAttribute.
ХотяКод для решения этой проблемы немного сложен, это приемлемо.Настоящая проблема заключается в сортировке .
Мне нужно отсортировать записи, имеющие заданный атрибут ExtraAttribute по этому атрибуту.Используя хранилище SQL, очевидно, что для самих Core Data невозможно отсортировать записи по значению связанного ExtraAttribute с заданным ключом.(Расстраивает, поскольку это возможно с другими хранилищами, и тривиально в самом SQL.)
Единственный способ, который я могу найти, - это отсортировать записи самостоятельно, а затем записать атрибут displayOrder
обратно в хранилище,и сортировать базовые данные по displayOrder
.Я делаю это с помощью следующего метода класса Entry
.(При этом используются некоторые методы и глобальные функции, которые не показаны, но, надеюсь, вы сможете получить суть. Если нет, спросите, и я уточню.)
NSInteger entryComparator(id entry1, id entry2, void *key) {
NSString *v1 = [[entry1 valueForPropertyName:key] description];
NSString *v2 = [[entry2 valueForPropertyName:key] description];
return [v1 localizedCompare:v2];
}
@implementation Entry
...
// Unified builtin property and extraAttribute accessor;
// expects human-readable name (since that's all ExtraAttributes have).
- (id)valueForPropertyName:(NSString *)name {
if([[Entry humanReadablePropertyNames] containsObject:name]) {
return [self valueForKey:
[Entry propertyKeyForHumanReadableName:name]];
} else {
NSPredicate *p = [NSPredicate predicateWithFormat:
@"key = %@", name];
return [[[self.extraAttributes filteredSetUsingPredicate:p]
anyObject] value];
}
}
+ (void)sortByPropertyName:(NSString *)name
inManagedObjectContext:(NSManagedObjectContext *)moc {
BOOL ascending = [Entry propertyIsNaturallyAscending:name];
[Entry sortWithFunction:entryComparator
context:name ascending:ascending moc:moc];
[[NSUserDefaults standardUserDefaults]
setObject:name
forKey:@"entrySortPropertyName"];
}
// Private method.
+ (void)sortWithFunction:(NSInteger (*)(id, id, void *))sortFunction
context:(void *)context
ascending:(BOOL)ascending
moc:(NSManagedObjectContext *)moc {
NSEntityDescription *entityDescription = [NSEntityDescription
entityForName:@"Entry" inManagedObjectContext:moc];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSError *error;
NSArray *allEntries = [moc executeFetchRequest:request error:&error];
[request release];
if (allEntries == nil) {
showFatalErrorAlert(error);
}
NSArray *sortedEntries = [allEntries
sortedArrayUsingFunction:sortFunction context:context];
int i, di;
if(ascending) {
i = 0; di = 1;
} else {
i = [sortedEntries count]; di = -1;
}
for(Entry *e in sortedEntries) {
e.displayOrder = [NSNumber numberWithInteger:i];
i += di;
}
saveMOC(moc);
}
@end
У этого есть две основные проблемы:
- Это медленно, даже с небольшими наборами данных.
- Это может занять произвольно большой объем памяти и, следовательно, сбой при больших наборах данных.
Я открыт длялюбые предложения, которые проще, чем вырвать Core Data и напрямую использовать SQL.Большое спасибо.
РЕДАКТИРОВАТЬ Спасибо за ваши ответы.Надеюсь, это прояснит вопрос.
Вот типичный набор данных: существует n объектов ввода, и у каждого есть отдельный набор пар ключ / значениесвязано с этим.Здесь я перечисляю пары ключ / значение под каждой записью:
Entry 1:
Foo => Hello world
Bar => Lorem ipsum
Entry 2:
Bar => La dee da
Baz => Goodbye cruel world
Здесь я хочу отсортировать записи по любому из ключей "Foo", "Bar" или "Baz".Если данная запись не имеет значения для ключа, она должна сортироваться как пустая строка.
Хранилище SQLite не может отсортировать по неизвестному ключу, используя -valueForUndefinedKey :;попытка сделать это приводит к NSInvalidArgumentException
, причина keypath Foo not found in entity <NSSQLEntity Entry id=2>
.
Как отмечено в документации, только фиксированный набор селекторов будет работать с дескрипторами сортировки, использующими хранилище SQL.
РЕДАКТИРОВАТЬ 2
Предположим, есть три экземпляра E1, E2 и E3 моей сущности, и пользователь присоединяет к каждому из этих экземпляров настраиваемые свойства «Имя» и «Год».Тогда у нас может быть:
E1 Bob 2010
E2 Alice 2009
E3 Charles 2007
Но мы хотим представить эти экземпляры пользователю, отсортированные по любому из этих пользовательских свойств.Например, пользователь может сортировать по имени:
E2 Alice 2009
E1 Bob 2010
E3 Charles 2007
или по дате:
E3 Charles 2007
E2 Alice 2009
E1 Bob 2010
и т. Д.