ios - 具有本地化字符串的核心数据排序描述符

标签 ios objective-c cocoa core-data

请给我一些建议。我对核心数据很陌生。

我有一个原则上运行良好的核心数据模型。它有一个实体“RoomType”。该实体只有一个 String 类型的属性和一个与实体“Room”的关系(很多)(其中反向关系是一个关系)。关系无关紧要。是字符串和 sortDescriptor 让我发疯。

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

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

这是自动生成的 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

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

这是我的 View Controller 中的 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。 这是 NSLog 的输出:

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
[...]

如您所见,英文原始数据排序正确,但德文翻译(“-”之后)排序不正确。

到目前为止很明显。但是我该如何解决这个问题?

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

最佳答案

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

但是如果数据是完全静态的(如您所说),您实际上并不需要获取结果 Controller 。您可以使用 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];
           }
];

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

关于ios - 具有本地化字符串的核心数据排序描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14481317/

相关文章:

ios - cocoa 中的UIGraphicsBeginContext、UIGraphicsEndImageContext?

cocoa - 上下文菜单的自定义 HitTest

iphone - 如何将 iPhone 应用程序与_every_ 文件类型相关联?

android - 基于 REST 的客户端-服务器同步

ios - 委托(delegate)方法不会触发(为空)。使用圆弧

ios - iOS 共享扩展的 NSExtensionActivationRule 不起作用

ios - UILabel 和 UITextField 的动画(Facebook POP 框架)

ios - Objective-C/Xcode 状态栏颜色与导航栏颜色相同

objective-c - 如何确定 NSButton 是否为复选框?

objective-c - 打印一个不可见的 NSView