我使用下面的代码从我的后端服务器(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); }]; }
谢谢您的帮助!
不幸的是,这是不可能的.请参阅setIncludesPendingChanges ::的文档Special Considerations
A value of
YES
is not supported in conjunction with the result type
NSDictionaryResultType
, including calculation of aggregate results
(such asmax
andmin
). For dictionaries, the array returned from the fetch reflects the current state in the persistent store, and does not take into account any pending changes, insertions, or deletions in the context.