【发布时间】:2012-12-23 12:04:41
【问题描述】:
我想做什么
我正在使用下面的代码将数据(历史外汇汇率)从我的后端服务器 (parse.com) 下载到我的应用的核心数据存储中。
应用程序检查本地存储的最新可用数据,并仅从服务器获取较新的数据。如果本地还没有存储数据,则从服务器获取所有数据。
代码的设置方式,它以 100 个对象为一组获取数据,将对象保存在 Core Data 中,获取现在本地存储数据的最新日期(通过使用 NSExpression)并获取下一批,直到服务器上不再有新对象 (objects.count = 0)。
因为获取速度很慢,我决定在后台线程上运行获取和 Core Data 保存(使用 iOS 5 提供的新 Core Data 多线程模型)。
从后端服务器获取工作正常,但是...
我的问题
似乎只有那些对象由存储在磁盘上(物理上在数据库中)的NSExpression 评估,而不是仍在内存中并将很快保存的对象。因此,fetch 主要从磁盘(内存)中检索“旧”值。
但是,当使用以下 fetch 代码(没有 NSExpression 和 NSDictionary 作为结果类型)时,我得到了当前和正确的值:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:localEntityName];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:YES];
request.sortDescriptors = @[sortDescriptor];
NSArray *results = [backgroundContext executeFetchRequest:request error:&error];
ForexHistory *forexHistoryItem = results.lastObject;
NSDate *lastLocalDate = forexHistoryItem.date;
NSLog(@"last local date results: %@",lastLocalDate);
下面的代码有什么问题,它使用NSExpression 和字典作为获取结果类型?
我的问题
如何确保查找最新本地可用日期的NSExpression 返回最新日期?
代码
- (void)seedForexHistoryInManagedObjectContext:(NSManagedObjectContext*)context {
NSString* const localEntityName = @"ForexHistory";
NSString* const parseEntityName = localEntityName;
NSString* const parseDateIdentifier = @"date";
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"date"];
NSExpression *maxPeriodExpression = [NSExpression expressionForFunction:@"max:"
arguments:@[keyPathExpression]];
NSString *expressionName = @"maxDate";
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
expressionDescription.name = expressionName;
expressionDescription.expression = maxPeriodExpression;
expressionDescription.expressionResultType = NSDateAttributeType;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:localEntityName];
request.propertiesToFetch = @[expressionDescription];
request.resultType = NSDictionaryResultType;
NSArray *currencies = @[@"AUD",@"EUR",@"NZD",@"GBP",@"BRL",@"CAD",@"CNY"];
dispatch_queue_t downloadQueue;
downloadQueue = dispatch_queue_create("download", NULL); // create serial dispatch queue
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.parentContext = context;
dispatch_async(downloadQueue,^{
[moc performBlockAndWait:^{
NSArray *objects;
do {
NSError *error;
NSArray *dateResults = [moc executeFetchRequest:request error:&error];
NSAssert(dateResults.count == 1,@"Request error!");
NSDate *lastLocalDate = dateResults.lastObject[expressionName];
NSLog(@"last local date results: %@",lastLocalDate);
PFQuery *query = [PFQuery queryWithClassName:parseEntityName];
query.limit = 100;
[query orderByAscending:parseDateIdentifier];
if (lastLocalDate) [query whereKey:parseDateIdentifier greaterThan:lastLocalDate]; // else query all
objects = [query findObjects];
[objects enumerateObjectsUsingBlock:^(PFObject *obj, NSUInteger idx, BOOL *stop) {
ForexHistory *forexHistory = [NSEntityDescription insertNewObjectForEntityForName:localEntityName
inManagedObjectContext:moc];
forexHistory.date = NULL_TO_NIL(obj[@"date"]);
[currencies enumerateObjectsUsingBlock:^(NSString *currency, NSUInteger idx, BOOL *stop) {
[forexHistory setValue:NULL_TO_NIL(obj[currency]) forKey:currency.lowercaseString];
}];
}];
NSError *saveError = nil;
[moc save:&saveError];
if (!saveError) NSLog(@"%lu forex rates saved successfully.",(unsigned long)objects.count);
else NSLog(@"Error when downloading historic forex rates: %@",error.localizedDescription);
} while (objects.count > 0);
}];
}
感谢您的帮助!
【问题讨论】:
标签: ios objective-c core-data grand-central-dispatch nsexpression