Вы могли использовать некоторый LINQ для получения списка:
var types = from type in this.GetType().Assembly.GetTypes()
where type is ISomeInterface
select type;
, Но действительно, который более читаем?
FetchedResultsController и его делегат не предназначены для использования при изменении пользовательской модели. См. справочный документ Apple . Ищите раздел User-Driven Updates (Пользовательские обновления). Так что если вы ищете какой-то волшебный, однострочный способ, то, к сожалению, его нет.
Что вам нужно сделать, так это сделать обновления в этом методе:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
userDrivenDataModelChange = YES;
...[UPDATE THE MODEL then SAVE CONTEXT]...
userDrivenDataModelChange = NO;
}
а также предотвратить уведомления, чтобы сделать что-нибудь, так как изменения уже сделаны пользователем:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
if (userDrivenDataModelChange) return;
...
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
if (userDrivenDataModelChange) return;
...
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
if (userDrivenDataModelChange) return;
...
}
Я только что реализовал это в моем приложении to-do (Quickie) и оно работает нормально.
Попробуйте ознакомиться с руководством по Core Data для iPhone здесь . В одном из разделов рассказывается о сортировке (с использованием NSSortDescriptor).
Вы также можете найти страницу Основные сведения о данных , которая будет полезной.
Я наконец отказался от FetchController в режиме редактирования, так как мне также нужно изменить порядок ячеек таблицы. Я бы хотел увидеть, как это работает. Вместо этого я сохранил изменяемый массив, являющийся текущим представлением таблицы, а также поддерживал согласованность атрибута CoreData orderItem.
NSUInteger fromRow = [fromIndexPath row];
NSUInteger toRow = [toIndexPath row];
if (fromRow != toRow) {
// array up to date
id object = [[eventsArray objectAtIndex:fromRow] retain];
[eventsArray removeObjectAtIndex:fromRow];
[eventsArray insertObject:object atIndex:toRow];
[object release];
NSFetchRequest *fetchRequestFrom = [[NSFetchRequest alloc] init];
NSEntityDescription *entityFrom = [NSEntityDescription entityForName:@"Lister" inManagedObjectContext:managedObjectContext];
[fetchRequestFrom setEntity:entityFrom];
NSPredicate *predicate;
if (fromRow < toRow) predicate = [NSPredicate predicateWithFormat:@"itemOrder >= %d AND itemOrder <= %d", fromRow, toRow];
else predicate = [NSPredicate predicateWithFormat:@"itemOrder <= %d AND itemOrder >= %d", fromRow, toRow];
[fetchRequestFrom setPredicate:predicate];
NSError *error;
NSArray *fetchedObjectsFrom = [managedObjectContext executeFetchRequest:fetchRequestFrom error:&error];
[fetchRequestFrom release];
if (fetchedObjectsFrom != nil) {
for ( Lister* lister in fetchedObjectsFrom ) {
if ([[lister itemOrder] integerValue] == fromRow) { // the item that moved
NSNumber *orderNumber = [[NSNumber alloc] initWithInteger:toRow];
[lister setItemOrder:orderNumber];
[orderNumber release];
} else {
NSInteger orderNewInt;
if (fromRow < toRow) {
orderNewInt = [[lister itemOrder] integerValue] -1;
} else {
orderNewInt = [[lister itemOrder] integerValue] +1;
}
NSNumber *orderNumber = [[NSNumber alloc] initWithInteger:orderNewInt];
[lister setItemOrder:orderNumber];
[orderNumber release];
}
}
NSError *error;
if (![managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort(); // Fail
}
}
}
Если у кого-нибудь есть решение, использующее fetchController, опубликуйте его.
Поздний ответ: возможно, вы могли бы сохранить ключ сортировки в виде строки. Вставить запись между двумя существующими строками можно тривиально, добавив в строку дополнительный символ, например, вставив «AM» между строками «A» и «B». Повторный заказ не требуется. Похожая идея может быть реализована с помощью числа с плавающей запятой или некоторой простой битовой арифметики с 4-байтовым целым числом: вставьте строку со значением ключа сортировки, которое находится на полпути между соседними строками.
Могут возникнуть патологические случаи, когда строка слишком длинная, число с плавающей запятой слишком мало или в int больше нет места, но тогда вы могли бы просто изменить нумерацию объекта и начать все сначала. Сканирование и обновление всех ваших записей в редких случаях намного лучше, чем отказываться от каждого объекта каждый раз, когда пользователь меняет порядок.
Например, рассмотрим int32. Использование старших 3 байтов в качестве начального порядка дает вам почти 17 миллионов строк с возможностью вставки до 256 строк между любыми двумя строками. 2 байта позволяют вставить 65000 строк между любыми двумя строками перед повторным сканированием.
Вот псевдокод, который я имел в виду для увеличения на 2 байта и для вставки на 2 байта:
AppendRow:item
item.sortKey = tail.sortKey + 0x10000
InsertRow:item betweenRow:a andNextRow:b
item.sortKey = a.sortKey + (b.sortKey - a.sortKey) >> 1
Обычно вы вызываете AppendRow, в результате чего получаются строки с sortKeys 0x10000, 0x20000, 0x30000 и т. д. Иногда вам потребуется InsertRow,