将行保存到Core Data时的时间延迟?

时间:2013-03-14 17:21:37

标签: ios core-data

我已经构建了一个在iOS 5.1,6.0和6.1上运行的简单琐事游戏。我使用Core Data,我有这两个对象:

@interface Category : NSManagedObject
@property (nonatomic, retain) NSString * category;
@property (nonatomic, retain) NSNumber * difficulty;
@property (nonatomic, retain) NSSet *questions;
@end

@interface Question : NSManagedObject
@property (nonatomic, retain) NSNumber * disabled;
@property (nonatomic, retain) NSNumber * displayTypeEasy;
@property (nonatomic, retain) NSNumber * displayTypeHard;
@property (nonatomic, retain) NSNumber * displayTypeMedium;
@property (nonatomic, retain) NSNumber * questionID;
@property (nonatomic, retain) Category *category;
@end

这个想法是每个问题只有一个类别(比如娱乐或体育)。类别 - 问题关系是一对多的;在我的样本数据中,有3个类别和20个问题。

我有一个设置窗口,允许用户更改他们想要播放的类别和/或更改给定类别的难度级别(即在此窗口中,对类别对象进行更改)。当用户按下OK时,执行以下代码:

- (IBAction)okPressed:(UIButton *)sender {
    NSError * error;
    BOOL wasSaveSuccessful = [[Constants database].managedObjectContext save:&error];
    NSLog(@"wasSaveSuccessful:%@   areChangesPending:%@", wasSaveSuccessful ? @"YES" : @"NO",
          [[Constants database].managedObjectContext hasChanges] ? @"YES" : @"NO");
}

顺便说一句:“[常量数据库]”是一个代表我的持久存储的UIManagedDocument。不可否认,这可能不是保持这种情况的最好方法,但我不相信这是我问题的根源。

接下来,用户可以按下新游戏按钮。然后执行此提取:

- (void) loadBatchOfQuestions
{
    if ([self.questionBatch count] == 0) { // self.questionBatch is an NSMutableArray
        // TEST #1
        for (Category * c in [[Category allCategories] objectEnumerator])
            NSLog(@"category:%@   difficulty:%d", c.category, [c.difficulty integerValue]);

        // TEST #2
        Question * q1 = [Question queryQuestionWithQuestionID:50150];
        NSLog(@"q1 difficulty:%d", [q1.category.difficulty integerValue]);

        NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"Question"];
        request.predicate = [NSPredicate predicateWithFormat:
                             @"(disabled == NO)"
                             @"AND (questionID > %ld)"
                             @"AND (((category.difficulty == %i) AND (displayTypeEasy != NULL))"
                             @" OR ((category.difficulty == %i) AND (displayTypeMedium != NULL))"
                             @" OR ((category.difficulty == %i) AND (displayTypeHard != NULL)))",
                             MAX_QUESTIONID_FOR_TEST_QUESTIONS,
                             DIFFICULTY_EASY, DIFFICULTY_MEDIUM, DIFFICULTY_HARD];

        NSError * error;
        [self.questionBatch addObjectsFromArray:[[Constants database].managedObjectContext executeFetchRequest:request error:&error]];
}

问题在于:如果在按下确定并离开设置窗口后,我等了大约10秒才按下新游戏,一切都很好; loadBatchOfQuestions中的fetch根据当前的Category数据返回正确的行。但是,如果我在关闭设置窗口后立即按下新游戏,我会看到旧数据(即我查询错误的问题)。

对于我在上面添加的NSLog语句:

  • 在okPressed中,我总是看到wasSaveSuccessful = YES和areChangesPending = NO(正如我所料)
  • 对于loadBatchOfQuestions中的TEST#1,我获取所有类别行(在本例中为3)并验证我看到了最新数据
  • 对于loadBatchOfQuestions中的TEST#2,我获取一个Question行以查看它是否显示正确的Category数据;确实如此。

然而,后续的提取会返回旧数据。

以下是我认为正在发生的事情:

  • 当我调用save时:在okPressed中,它实际上是将更改写入内存缓存。然后,这些更改将在3-10秒的时间内异步写入Core Data持久存储。
  • TEST#1和TEST#2中的提取非常基本;他们只是用一个简单的谓词来获取对象(在TEST#1的情况下没有谓词,因为我想要所有的行,而在TEST#2的情况下是@“questionID =%ld”)。对于这些情况,fetch可以在从持久性存储中检索数据之前检查缓存中的当前数据。 (NSManagedObjectContext.executeFetchRequest的文档说“如果上下文中的对象已被修改,则根据其修改状态评估谓词,而不是针对持久性存储中的当前状态。因此,如果上下文中的对象已被修改,它满足获取请求的条件,即使尚未将更改保存到商店并且商店中的值不符合条件,请求也会检索它。相反,如果上下文中的对象已被修改,它与获取请求不匹配,即使商店中的版本匹配,获取请求也不会检索它。“)
  • 但是,我在loadBatchOfQuestions中的主谓词足够复杂,以至于fetch在评估时不会/不能查看缓存,因此我会看到旧数据。但是,如果我等待足够长的时间,持久存储将在执行此提取时更新。

我的问题:

  • 我的分析有意义吗?或者有人在我的代码中看到其他一些错误/缺陷吗?
  • 如果我是对的,有办法解决这个问题吗?也许调用委托方法告诉我什么时候数据“真的”保存到持久存储?或者我可能需要设置UIManagedDocument或NSManagedObjectContext的属性?

0 个答案:

没有答案