5

私がやろうとしていること

以下のコードを使用して、バックエンド サーバー (parse.com) からアプリのコア データ ストアにデータ (過去の外国為替レート) をダウンロードしています。

アプリは、ローカルに保存されている最新の利用可能なデータをチェックし、サーバーから新しいデータのみをフェッチします。ローカルにまだデータが保存されていない場合は、サーバーからすべてのデータを取得します。

コードの設定方法は、100 個のオブジェクトのバッチでデータをフェッチし、コア データにオブジェクトを保存し、データが現在ローカルに保存されている新しい最新の日付を取得し (を使用してNSExpression)、新しいデータがなくなるまで次のバッチをフェッチします。オブジェクトはサーバーに残されます ( objects.count = 0)。

フェッチは遅いため、フェッチと Core Data の保存をバックグラウンド スレッドで実行することにしました (iOS 5 で提供される新しい Core Data マルチスレッド モデルを使用)。

バックエンド サーバーからのフェッチは正常に機能しますが、...

私の問題

NSExpressionこれらのオブジェクトのみがディスク上に (物理的にはデータベースに) 保存されており、まだメモリ内にあり、すぐに保存されるオブジェクトは評価されないようです。したがって、フェッチはほとんどの場合、ディスク (メモリ) から「古い」値を取得します。

ただし、次のフェッチのコードを使用すると (noNSExpressionおよびNSDictionaryas result 型を使用)、現在の正しい値が取得されます。

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と辞書を fetch resultType として使用する以下のコードの何が問題になっていますか?

私の質問

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);
          }];
}

ご協力ありがとうございました!

4

2 に答える 2

2

残念ながら、これは不可能です。次のドキュメントを参照してくださいsetIncludesPendingChanges:

特別な考慮事項

の値は、集計結果の計算 ( や など) を含め、YES結果タイプ と組み合わせて使用​​することはできません 。ディクショナリの場合、フェッチから返される配列は永続ストアの現在の状態を反映し、コンテキスト内の保留中の変更、挿入、または削除は考慮されません。NSDictionaryResultTypemaxmin

于 2013-01-02T12:51:44.713 に答える
0

保留中の変更を含める:[request setIncludePendingChanges:YES];フェッチを行う前に挿入します。

これにより、保存されていない変更がフェッチに含まれることが保証されます。

于 2012-12-23T12:07:47.883 に答える