ios - 基于 NSExpression 的核心数据提取不检索当前值(iOS 5、GCD)

标签 ios objective-c core-data grand-central-dispatch nsexpression

我想做什么

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

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

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

因为抓取很慢,我决定在后台线程上运行抓取和 Core Data 保存(使用 iOS 5 提供的新 Core Data 多线程模型)。

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

我的问题

似乎只有那些存储在磁盘上(物理上在数据库中)的对象被 NSExpression 评估,而不是仍在内存中并将很快被保存的对象。因此,提取主要是从磁盘(内存)中检索“旧”值。

但是,当使用以下获取代码时(没有 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);

我下面的代码有什么问题,它使用 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 as max and min). 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.

关于ios - 基于 NSExpression 的核心数据提取不检索当前值(iOS 5、GCD),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14010809/

相关文章:

ios - 我无法在 MagicalRecord 中找到 FirstByAttribute

ios - 在 Swift 中,如何确定设备屏幕的物理尺寸?

ios - 用 NSDictionaries 将一个 NSArray 整理成 2 个 NSArray

ios - 关于 CollectionViewCell

ios - 在 UITableViewController 中启用滚动

iphone - 无法消除 transient 属性 getter impls 中原始值访问器的编译器警告

ios - 来自 NSMutablearray 的 setheader 值

ios - 来自 .dae 的具有视频纹理的 SCNNode 不规则平面

ios - NSManagedObject 类似通用对象

ios - Swift:CoreData – ManagedObjectContext-错误