0

私は iOS 開発と Core Data テクノロジーを使い始めたところです。

私がやろうとしているのは、オブジェクトを Core Data に挿入し、同じコンテキスト内でフェッチ要求を実行して、新しく挿入されたオブジェクトを探すことです。

オブジェクトを挿入するために使用しているコードは次のとおりです。

+(Reward*) rewardForAction: (Actions) action
    inManagedObjectContext: (NSManagedObjectContext *) context {

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Reward"];
    NSPredicate *actionPredicate =
        [NSPredicate predicateWithFormat:@"action = %@",
         [NSString stringWithFormat:@"%i", action]];

    NSPredicate *todayPredicate =
        [NSPredicate predicateWithFormat:@"when > %@",
         [NSDate today]];

    NSLog(@"Today's midnight :%@", [NSDate today]);
    request.predicate =
        [NSCompoundPredicate andPredicateWithSubpredicates:
         [NSArray arrayWithObjects: actionPredicate, todayPredicate, nil]];

    NSError *error = nil;
    NSArray *matches = [context executeFetchRequest: request error: &error];

    Reward *reward = nil;
    if(!matches) {
        NSLog(@"ERROR: failed to retrieve rewards");
    } else if(matches.count > 0) {
        NSLog(@"WRONG: reward already exists");
    } else {
        reward = [NSEntityDescription insertNewObjectForEntityForName:@"Reward"
                                               inManagedObjectContext:context];
        reward.action = [NSNumber numberWithInt:action];
        reward.when = [NSDate date];
        reward.pointsEarned = [Reward getPointsForAction:action];
    }

    [Stats track: context];

    [context save:nil];

    return reward;
}

このコードは、最初に何らかのアクションに対して今日すでに報酬が与えられているかどうかを確認し、そうでない場合は報酬を与えます。

このメソッドを同じパラメーターで 2 回呼び出します。

[rewardrewardForAction:APPLICATION_LAUNCH inManagedObjectContext: self.db.managedObjectContext]; [rewardrewardForAction:APPLICATION_LAUNCH inManagedObjectContext: self.db.managedObjectContext];

オブジェクトが 1 つだけ挿入されると予想されます。

しかし、実際には Core Data に 2 つのオブジェクトを挿入します。デバッガーでは、2 番目のフェッチ要求が既に存在する場合、オブジェクトを返さないことがわかります。

NSFetchRequest はデータ ストアの変更を認識せず、古いデータを操作するようです。何か不足していますか?

編集: NSManagedObjectContextObjectsDidChangeNotification のオブザーバーも設定しました。それが呼び出されると、ポイントの合計を計算して UI に反映します。残念ながら、 sum には挿入されたオブジェクトからのポイントも含まれていません。合計を計算するコードは次のとおりです。

+(NSInteger) getPoints: (NSManagedObjectContext *) context {
    Stats * stats= [Stats get: context];

    NSArray *args = [NSArray arrayWithObject:
                     [NSExpression expressionForKeyPath:@"pointsEarned"]];
    NSExpression *ex = [NSExpression expressionForFunction:@"sum:"
                                                 arguments:args];

    NSExpressionDescription *ed = [[NSExpressionDescription alloc] init];
    [ed setName:@"result"];
    [ed setExpression:ex];
    [ed setExpressionResultType:NSInteger32AttributeType];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setPropertiesToFetch:[NSArray arrayWithObject:ed]];
    [request setResultType:NSDictionaryResultType];

    /*if([stats intervalStartDate]) {
         NSPredicate *predicate =
            [NSPredicate predicateWithFormat:@"when >= %@", [stats intervalStartDate]];
             [request setPredicate:predicate];
    }*/    

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Reward"
                                              inManagedObjectContext:context];
    [request setEntity:entity];

    NSArray *results = [context executeFetchRequest:request error:nil];

    if(results && results.count > 0) {
        NSDictionary *resultsDictionary = [results objectAtIndex:0];
        NSNumber *resultValue = [resultsDictionary objectForKey:@"result"];
        return [resultValue intValue];
    } else {
        return 0;
    }    
}

奇妙なことに、シミュレーターでアプリを停止して再度実行すると、. 期待どおりにすべてのポイントを見ることができます。

4

1 に答える 1

4

から

reward.action = [NSNumber numberWithInt:action];

「アクション」属性はとして保存されていると思いますNSNumber。対応する述語で同じデータ型を使用する必要があります。

NSPredicate *actionPredicate = [NSPredicate predicateWithFormat:@"action = %@",
                                          [NSNumber numberWithInt:action]];

追加:「NSManagedObjectContextDidSaveNotification」と「NSManagedObjectContextObjectsDidChangeNotification」についての質問:

フェッチ リクエストNSDictionaryResultTypeは、永続ストア内の現在の状態のみをフェッチし、コンテキスト内の保留中の変更、挿入、または削除を考慮しません。

この情報は、たとえば のドキュメントにありsetIncludesPendingChanges:ます。

これは、取得リクエストが保存された変更のみを参照する理由を説明しています。

于 2012-09-05T18:32:41.633 に答える