NSManagedObjectContext不会向观察者通知瞬态变化

时间:2013-11-21 14:59:28

标签: ios core-data formatting nsnotificationcenter key-value-observing

我正在尝试清理一些瞬态属性重新计算事件。在开发过程中,我刚刚对几乎所有的更改进行了非常广泛的更新。现在我正在尝试确定最佳实践,检查相关密钥并根据需要进行更新。我的应用程序对象使用子属性和父属性加载了许多计算,其中单个更改可能导致许多级联重新计算。

我认为我理解得很好,指的是Apple文档here,我已经尝试了@Marcus S. Zarra在其他一些StackOverflow帖子上看到的模式,例如this。我看到马库斯还发表了一篇关于这个主题的文章here

我现在所拥有的是:

#pragma mark _ worksheetTotal (transient)

+(NSSet *)keyPathsForValuesAffectingWorksheetTotal
{
    // local, non-transient, dependent keys here
    return [NSSet setWithObjects:@"dailySustenance", nil];
}

-(void)updateWorksheetTotal
{
    NSDecimalNumber *lineItemTotal = [self.items valueForKeyPath:@"@sum.lineHoursCost"];
    NSDecimalNumber *total = [lineItemTotal decimalNumberByAdding:self.dailySustenance];

    [self setWorksheetTotal:total];
}

-(void)setWorksheetTotal:(NSDecimalNumber *)newWorksheetTotal
{
    if ([self worksheetTotal] != newWorksheetTotal) {
        [self willChangeValueForKey:@"worksheetTotal"];
        [self setPrimitiveWorksheetTotal:newWorksheetTotal];
        [self didChangeValueForKey:@"worksheetTotal"];
    }
}

-(NSDecimalNumber *)worksheetTotal
{
    [self willAccessValueForKey:@"worksheetTotal"];
    NSDecimalNumber *result = [self primitiveWorksheetTotal];
    [self didAccessValueForKey:@"worksheetTotal"];

    return result;
}

我认为这直接来自文档用例,但我的观察员没有收到有关workheetTotal更改的通知。

当对lineItem进行更改时,会收到该通知,并在此处调用响应updateWorksheetTotal。我希望这会触发workheetTotal现在已经改变的上下文的另一个通知,但事实并非如此。我尝试了很多我见过的代码变体和组合,但我做的任何事情似乎都没有让NSManagedObjectContext认为我对worksheetTotal的更新是值得向观察者报告的更改。

我在这里缺少什么?

以下是监听Parent对象更改的相关代码。

- (void) objectContextDidChange: (NSNotification *) notification
{
    NSSet *updatedObjects = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];
    // Next look for changes to worksheet that may affect our calculated fields
    NSPredicate *worksheetPredicate = [NSPredicate predicateWithFormat:@"entity.name == %@ && estimate == %@", @"LaborWorksheet", self];
    NSPredicate *materialsPredicate = [NSPredicate predicateWithFormat:@"entity.name == %@ && estimate == %@", @"MaterialLineItems", self];
    NSPredicate *combinedPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:[NSArray arrayWithObjects:worksheetPredicate, materialsPredicate, nil]];
    NSSet *myWorksheets = [updatedObjects filteredSetUsingPredicate:combinedPredicate];
    // These are the relevant keys in this estimates labor and materials worksheet
    NSSet *relevantKeys = [NSSet setWithObjects:@"worksheetTotal", @"totalEquipmentcost", nil];
    BOOL clearCache = NO;
    if (myWorksheets.count != 0) {
        for (NSManagedObject *worksheet in myWorksheets) {
            NSLog(@"got some");
            // Here is where it fails, worksheetTotal is not in changedValues.allKeys. It is an empty set.
            // Not sure how that could be when I got it from updatedObjects set of userInfo. How could it have no changed values?
            NSSet *changedKeys = [NSSet setWithArray:worksheet.changedValues.allKeys];
            if ([changedKeys intersectsSet:relevantKeys]) {
                clearCache = YES;
                NSLog(@"found some, set to clear cache");
                // no need to continue checking
                break;
            }
        }
    }

    if (clearCache) {
      // I would update dependent keys here but it is never reached

    }
 }

2 个答案:

答案 0 :(得分:2)

changedValues方法的文档说:

  

此方法仅报告对定义为的属性的更改   接收器的持久属性,而不是瞬态变化   属性或自定义实例变量。这种方法没有   不必要的火灾关系错误。

由于您的财产是短暂的,它不会出现在那里。我建议使用KVO来监控这些属性的变化。

答案 1 :(得分:1)

您在didAccessValueForKey之前返回。存储到变量并在didAccessValueForKey之后返回它,如

-(NSDecimalNumber *)worksheetTotal
{
    [self willAccessValueForKey:@"worksheetTotal"];
    NSDecimalNumber *yourVariable = [self primitiveWorksheetTotal];
    [self didAccessValueForKey:@"worksheetTotal"];
    return yourVariable;
}

我希望它有效。

修改

-(void)setWorksheetTotal:(NSDecimalNumber *)newWorksheetTotal

考虑改变

if ([self worksheetTotal] != newWorksheetTotal) {

if (worksheetTotal != newWorksheetTotal) {