1

我需要一些建议。我对核心数据比较陌生。

我有一个原则上运行良好的核心数据模型。它有一个实体“RoomType”。该实体只有一个 String 类型的属性和一个与实体“Room”的关系(多)(其中逆是单关系)。关系无所谓。让我抓狂的是字符串和 sortDescriptor。

数据库内容为英文。该表是一些设置表,在安装应用程序时动态填充,用户永远不会更改。对于任何德语和第三语言,我都需要翻译这些数据。我为此目的使用 NSLocalizedString 宏并且它运行良好 - 除了按其翻译值对数据进行排序。

(对于未来的版本,我将允许用户添加记录。但那些手动添加的记录不需要翻译。)

这是自动生成的 RoomType.h:

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Room;

@interface RoomType : NSManagedObject

@property (nonatomic, retain) NSString * typeName;
@property (nonatomic, retain) NSSet *rooms;
@end

@interface RoomType (CoreDataGeneratedAccessors)

- (void)addRoomsObject:(Room *)value;
- (void)removeRoomsObject:(Room *)value;
- (void)addRooms:(NSSet *)values;
- (void)removeRooms:(NSSet *)values;

@end

没什么不寻常的,我会说。

这是我的视图控制器中的 fetchedResultsController getter 方法:

- (NSFetchedResultsController *)fetchedResultsController
{
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.

    self.managedObjectContext = [(AppDelegate*) [[UIApplication sharedApplication] delegate] managedObjectContext];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"RoomType" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor;
    sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"typeName" ascending:YES];
    [fetchRequest setSortDescriptors: @[sortDescriptor]];

    // Set the predicate // No predicate because we want to fetch all items
    //NSPredicate *predicate =
    //[NSPredicate predicateWithFormat:@"suite == %@", self.detailItem];
    //[fetchRequest setPredicate:predicate];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Suite"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _fetchedResultsController;
}

数据被送入选择器:

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {

    return 1;
}

- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {

    int anzahl = [[self.fetchedResultsController fetchedObjects] count];
    return anzahl;
}

- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {

    NSManagedObject *object = [[self.fetchedResultsController fetchedObjects] objectAtIndex:row];

    RoomType    *roomType   = (RoomType*) object;
    NSLog(@"%@ - %@", roomType.typeName, NSLocalizedString(roomType.typeName, @"Room-Type"));

    return NSLocalizedString(roomType.typeName, @"Room-Type");  // <-- HERE COMES THE TRANSLATION!
}

- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {

    Room *theRoom = (Room*) [self detailItem];

    //Ignore the component cause there is only one.
    theRoom.roomType = [[self.fetchedResultsController fetchedObjects] objectAtIndex:row];

}

请记下数据库内容本地化的 NSLocalzedString。这是 NSLogs 的输出:

2013-01-23 14:38:38.179 Wohnungsprotokoll[1311:c07] attic - Dachboden
2013-01-23 14:38:38.184 Wohnungsprotokoll[1311:c07] balcony - Balkon
2013-01-23 14:38:38.187 Wohnungsprotokoll[1311:c07] bath room - Badezimmer
2013-01-23 14:38:39.659 Wohnungsprotokoll[1311:c07] bed room - Schlafzimmer
2013-01-23 14:38:39.831 Wohnungsprotokoll[1311:c07] cellar - Keller
2013-01-23 14:38:40.789 Wohnungsprotokoll[1311:c07] children room - Kinderzimmer
2013-01-23 14:38:41.043 Wohnungsprotokoll[1311:c07] closet - Kammer
[...]

如您所见,英语中的原始数据已正确排序,但德语翻译(在“-”之后)未正确排序。

到目前为止很明显。但是我该如何解决呢?

有没有什么聪明的方法可以按数据库内容的本地化值进行排序?我的意思是另一种方法,而不是将数据复制到数组中并随后对该数组进行排序。

4

1 回答 1

1

Core Data 获取请求(对于基于 SQLite 的存储)只能对持久属性进行排序,并且也不能使用基于 Objective-C 的排序描述符。所以(据我所知)没有办法让获取的结果控制器返回根据函数排序的对象,例如NSLocalizedString. (唯一的方法是将翻译后的字符串作为附加属性存储在核心数据实体中。)

但是,如果数据是完全静态的(如您所说),您实际上并不需要获取结果控制器。您可以使用 获取对象,executeFetchRequest然后根据需要对结果数组进行排序:

NSArray *unsortedRooms = [self.managedObjectContext executeFetchRequest:fetchRequest error:NULL];
NSArray *sortedRooms = [unsortedRooms sortedArrayUsingComparator:
           ^NSComparisonResult(RoomType *rt1, RoomType *rt2) {
               NSString *name1 = NSLocalizedString(rt1.typeName, @"Room-Type");
               NSString *name2 = NSLocalizedString(rt2.typeName, @"Room-Type");
               return [name1 compare:name2];
           }
];

(获取结果控制器的优点是它监视其关联的托管对象上下文中对象的更改,并将结果集的更改报告给其委托,通常是表视图。但在您的情况下,对象不会更改。)

于 2013-01-23T14:21:09.627 回答