基于NSExpression的Core Data fetch不检索当前值(iOS 5,GCD)

Ale*_*exR 5 core-data objective-c grand-central-dispatch ios nsexpression

我想做什么

我使用下面的代码从我的后端服务器(parse.com)下载数据(历史外汇汇率)到我的应用程序的核心数据存储.

该应用程序检查本地存储的最新可用数据,并仅从服务器获取较新的数据.如果还没有本地存储的数据,它将从服务器获取所有数据.

设置代码的方式是,它以100个对象的批量获取数据,将对象保存在Core Data中,获取当前存储数据的新的最新日期(通过使用NSExpression)并获取下一批,直到不再有新的对象留在服务器上(objects.count = 0).

由于提取速度很慢,我决定在后台线程上运行提取和Core Data保存(使用iOS 5提供的新Core Data多线程模型).

从后端服务器获取工作正常,但......

我的问题

似乎只有那些对象由NSExpression存储在磁盘上(物理上存储在数据库中)而不是仍在内存中的对象进行评估,并且很快就会被保存.因此,fetch主要从磁盘(内存)中检索"旧"值.

但是,当使用以下fetch代码(没有NSExpressionNSDictionary作为结果类型)时,我得到当前和正确的值:

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);
Run Code Online (Sandbox Code Playgroud)

我的代码下面有什么问题,它使用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);
          }];
}
Run Code Online (Sandbox Code Playgroud)

谢谢您的帮助!

Mar*_*n R 2

不幸的是,这是不可能的。请参阅以下文档setIncludesPendingChanges:

特别注意事项

YES不支持 值与结果类型 结合使用NSDictionaryResultType,包括聚合结果的计算(例如maxmin)。对于字典,从获取返回的数组反映了持久存储中的当前状态,并且不考虑上下文中任何挂起的更改、插入或删除。