2012-09-05 45 views
0

我剛開始玩iOS開發和核心數據技術。插入的對象不反映在查詢結果與NSFetchRequest

我想要做的是將對象插入到核心數據,然後在相同的上下文中尋找新插入的對象運行獲取請求。

這裏是我使用插入對象的代碼:

+(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; 
} 

此代碼首先檢查是否獎勵今天已經給出的一些動作,如果沒有它給出了一個獎勵。

調用此方法兩次,用相同的參數,這樣

[獎勵rewardForAction:APPLICATION_LAUNCH inManagedObjectContext:self.db.managedObjectContext]; [獎勵rewardForAction:APPLICATION_LAUNCH inManagedObjectContext:self.db.managedObjectContext];

預計會導致只插入一個對象。

但是,事實上,它將兩個對象插入到核心數據中。在調試器中,我看到第二個獲取請求在已經存在的情況下不會返回任何對象。

看起來像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; 
    }  
} 

奇怪的是,當我停止在模擬器上的應用程序,並再次運行它。我可以按照我的預期看到所有的觀點。

+1

我懷疑問題在於一個或兩個謂詞。嘗試註釋掉request.predicate =並查看是否可以添加兩行?如果不是,則診斷這些謂詞。 – CSmith

+0

事實上,問題是與actionPredicate指出的答案 –

+0

我有另一個難題,我把編輯 –

回答

4

reward.action = [NSNumber numberWithInt:action]; 

我承擔的 「動作」 屬性存儲爲NSNumber。你應該在相應的謂語使用相同的數據類型:

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

新增:您關於「NSManagedObjectContextDidSaveNotification」與「NSManagedObjectContextObjectsDidChangeNotification」問題:

取指與NSDictionaryResultType要求只取當前狀態持久性存儲,並且不考慮上下文中的任何未決更改,插入或刪除。

你可以找到這個信息例如在setIncludesPendingChanges:的文檔中。

這解釋了爲什麼您的提取請求只能看到已保存的更改。

+0

感謝Martin的快速幫助,從字符串參數更改爲NSNumber確實有所幫助。謂詞是否被翻譯成SQL語法和核心數據,還有其他一些機制?我不知道如何正確,因此我只是使用了字符串,假設它轉換爲SQL聯合身份驗證,應該沒有問題,因爲SQLITE不是強類型的。 –

+0

在插入最初沒有提到的對象後,我有另一個查詢Core Data的問題。我已將它添加到更新中,如果可以查看它,將很感激。 –