当一对多相关的 NSManagedObject 子类发生更改时,如何更新 NSManagedObject 子类?

Posted

技术标签:

【中文标题】当一对多相关的 NSManagedObject 子类发生更改时,如何更新 NSManagedObject 子类?【英文标题】:How to Update NSManagedObject subclass when a to-many related NSManagedObject subclass changes? 【发布时间】:2014-07-20 20:54:26 【问题描述】:

我想在“Day”中保持正确的 emoAvg。以下是我希望完成的工作:

    每当“情绪”与 “一天”……一天可以有很多情绪。 每当从“Day”中删除“Emotion”时,更新“Day”的 emoAvg 每当“Emotion”的情绪属性发生变化时,更新“Day”的 emoAvg。

我想将所有这些代码保留在模型层中,并且我已经能够通过调用以下代码将情绪与日子联系起来,该代码在创建情绪时将日子附加到情绪上。

我无法为“Day”与“Emotion”的一对多关系编写自定义访问器。我被困在 Xcode 4.6.2 中,并且此版本中似乎不存在复制/粘贴自定义 ObjectiveC 访问器功能。

构建此代码的好方法是什么?

 - (void)setDate:(NSDate *)date

    [self willChangeValueForKey:@"date"];
    [self setPrimitiveValue:date forKey:@"date"];

    [self associateDay];

    [self didChangeValueForKey:@"date"];



-(void)associateDay

    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];

    NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:self.date];

    //Start of Day
    [dateComponents setHour:0];
    [dateComponents setMinute:0];
    [dateComponents setSecond:0];
    NSDate *startOfDay = [calendar dateFromComponents:dateComponents];
    //NSLog(@"Start of Day:       %@", [dateFormatter stringFromDate:startOfDay]);

    //End of Day
    [dateComponents setHour:23];
    [dateComponents setMinute:59];
    [dateComponents setSecond:59];
    NSDate *endOfDay = [calendar dateFromComponents:dateComponents];
    //NSLog(@"End of Day:         %@", [dateFormatter stringFromDate:endOfDay]);

    //Find all Day Entities that fall on the same calendar date
    NSPredicate *datePredicate = [NSPredicate predicateWithFormat:@"date > %@ AND date < %@", startOfDay, endOfDay];
    NSFetchRequest *fetchDays = [[NSFetchRequest alloc]initWithEntityName:@"Day"];
    fetchDays.predicate = datePredicate;
    NSManagedObjectContext *context = [(id)[UIApplication sharedApplication].delegate managedObjectContext];
    NSArray *daysFound = [context executeFetchRequest:fetchDays error:nil];

    if ([daysFound count] == 1)
    
        Day *dayWithMatchingDate = [daysFound objectAtIndex:0];
        self.day = dayWithMatchingDate;
        NSLog(@"Found %d matching days",[daysFound count]);
    

    if ([daysFound count] > 1)
    
        NSLog(@"Found %d matching days...Something needs fixing",[daysFound count]);
    

    if ([daysFound count] < 1)
    
        NSLog(@"Found %d matching days...Making a new Day and associating it",[daysFound count]);
        NSManagedObjectContext *context = [(id)[UIApplication sharedApplication].delegate managedObjectContext];
        Day *newDay = [NSEntityDescription insertNewObjectForEntityForName:@"Day" inManagedObjectContext:context];
        newDay.date = self.date;
        self.day = newDay;
    

【问题讨论】:

【参考方案1】:

我认为将Day 建模为数据模型的一部分不一定是个好主意。现有的日期属性应该足以用于选择、过滤和其他逻辑。

不过,您走在正确的轨道上。关键是覆盖设置器。您需要覆盖EmotionDay 中的以下设置器(我的提示:在情感Emotion+Additions 上创建一个类别,以将此代码与基本模型类分开)。

    setEmotionEmotion removeEmotionsObjectDay addEmotionsObjectDay

例如

-(void)removeEmotionsObject:(Emotion)value 
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
    [self willChangeValueForKey:@"emotions" 
        withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
    [[self primitiveEmotions] removeObject:value];
    [self didChangeValueForKey:@"emotions" 
        withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];

有关这些访问器的更多详细信息,请参阅 Core Data Programming Guide 的 relevant section。

【讨论】:

蒙迪,感谢您的回复。在提出问题之前,我阅读了您链接的部分。你能解释一下“[[self primitiveEmotions] removeObject:value];”我不清楚该代码的来源。 每个托管对象attribute 都由setPrimitiveAttribute 等方法自动支持。 removeObject 是一个常规的 NSSet 实例方法。【参考方案2】:

我能够得到我要求工作的代码。 然而,这是一团乱麻,我认为最好使用 NSNotificationCenter 并观察相关对象的变化。 这是有效的代码。 必须给 Mundi 提供帮助以帮助我。

- (void)addEmotionsObject:(Emotion *)value

    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];

    [self willChangeValueForKey:@"emotions" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];

    [[self primitiveEmotions] addObject:value];

    [self calculateEmotionalAverage];

    [self didChangeValueForKey:@"emotions" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];


- (void)removeEmotionsObject:(Emotion *)value

    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];

    [self willChangeValueForKey:@"emotions" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];

    [[self primitiveEmotions] removeObject:value];

    [self calculateEmotionalAverage];

    [self didChangeValueForKey:@"emotions" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];




- (void)addEmotions:(NSSet *)value

    [self willChangeValueForKey:@"emotions" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];

    [[self primitiveEmotions] unionSet:value];

    [self calculateEmotionalAverage];

    [self didChangeValueForKey:@"emotions" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];




- (void)removeEmotions:(NSSet *)value

    [self willChangeValueForKey:@"emotions" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];

    [[self primitiveEmotions] minusSet:value];

    [self calculateEmotionalAverage];

    [self didChangeValueForKey:@"emotions" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];



-(void)calculateEmotionalAverage

    float emotionalTotal = 0;
    for (Emotion *emo in self.emotions)
    
        if ([emo.emotion isEqualToString:@"Joy = 22"])
            emotionalTotal += 22.0;
        
        NSLog(@"%f",emotionalTotal);
    

【讨论】:

以上是关于当一对多相关的 NSManagedObject 子类发生更改时,如何更新 NSManagedObject 子类?的主要内容,如果未能解决你的问题,请参考以下文章

使用父 NSManagedObject 上的关系枚举子实体 VS 使用 NSFetchRequest

NSManagedObject 子类中的泛型类型

CoreData - NSManagedObject 子对象一次只存储在一个对象中

如何为一对多关系正确配置 Core Data 数据模型和 NSManagedObject?

如何将 NSManagedObject 传递给 NSPredicate 以及如何保存一对多的实体

自定义 NSManagedObject 类从 NSOrderedSet 添加/删除对象