快速 NSData 解档

Fast NSData unarchiving

我从这样的 class 实例创建 NSData

NSData* data = [NSKeyedArchiver archivedDataWithRootObject:db];
[data writeToFile:@"/Users/.../db.data" atomically:true];

然后我需要加载这个实例:

NSURL* dbUrl = [[NSBundle mainBundle]URLForResource:@"db" withExtension:@"data"];
NSData* dbData = [NSData dataWithContentsOfURL:dbUrl];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    self.db = [NSKeyedUnarchiver unarchiveObjectWithData:dbData];
});

此加载持续 cca。约 70MB 文件大小需要 6 秒。它很慢!我试图将 db 实例分成两个不同的部分(~35MB)并像这样加载它们:

self.db = [[Database alloc]init];
NSURL* dbUrl1 = [[NSBundle mainBundle]URLForResource:@"db1" withExtension:@"data"];
NSData* dbData1 = [NSData dataWithContentsOfURL:dbUrl1];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    self.db.nodes = [NSKeyedUnarchiver unarchiveObjectWithData:dbData1];
});
NSURL* dbUrl2 = [[NSBundle mainBundle]URLForResource:@"db2" withExtension:@"data"];
NSData* dbData2 = [NSData dataWithContentsOfURL:dbUrl2];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    self.db.trips = [NSKeyedUnarchiver unarchiveObjectWithData:dbData2];
});

通过这种方式加载持续 cca。 3 秒(快 2 倍)。你知道其他加载速度更快的方法吗?

编辑 1:

我不确定它是否有帮助,但存档对象有两个 NSMutableArray 实例。第一个包含很多 Node 个对象:

@interface DatabaseNode : NSObject <NSCoding>

@property (assign, nonatomic) NSInteger index;
@property (strong, nonatomic) NSString* name;
@property (assign, nonatomic) double lat;
@property (assign, nonatomic) double lon;

@end

而第二个包含很多 Trip 个对象:

@interface DatabaseTrip : NSObject <NSCoding>

@property (assign, nonatomic) NSInteger index;
@property (strong, nonatomic) NSString* name;
@property (assign, nonatomic) NSInteger service;
@property (strong, nonatomic) NSMutableArray* departureTimes; //Contains NSDate

@end

鉴于您需要应用程序会话开始时内存中的所有数据,您将不得不采用 NSKeyedArchiver 以外的解决方案。 NSKA 旨在归档复杂的对象图,因此经过优化以解决不同的问题。

对于您的情况,我建议在构建阶段将静态数据写入无需解析即可映射到内存的文件格式。然后,在运行时,映射文件并通过将其转换为 Foundation 类型中的最小封装。

对于字符串,字符串 table 之类的解决方案就足够了。日期可能有点棘手,也许。我会测试一下基于时间间隔的创建方法是否很快。如果是,那么您可以将日期作为数组(不是 NSArrays,而是 NSTimeIntervals 的平面 C 数组)存储在映射文件中并进行修复。

当然,您也可以根据应用中的访问模式跳过某些数据子集的修复。如果您的用户并不真正一次查看所有日期,则无需在加载时修复它们,但可以按需创建它们。