核心数据排序描述符与本地化字符串

时间:2013-01-23 13:48:27

标签: ios objective-c cocoa core-data

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

我有一个原则上工作正常的核心数据模型。它有一个实体“RoomType”。该实体只有一个String类型的属性和一个与实体“Room”的关系(很多)(其中inverse是一个关系)。这种关系并不重要。字符串和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
[...]

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

到目前为止显而易见。但是我该如何解决这个问题呢?

是否有任何智能方法可以根据数据库内容的本地化值对其进行排序? 我的意思是另一种方法,而不是将数据复制到数组中,然后对该数组进行排序。

1 个答案:

答案 0 :(得分:1)

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

但是如果数据是完全静态的(正如你所说),你真的不需要一个获取的结果控制器。您可以使用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];
           }
];

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