【问题标题】:Set a lastModificationDate attribute after NSManagedObjectsDidChangeNotification creates an infinite loop在 NSManagedObjectsDidChangeNotification 创建无限循环后设置 lastModificationDate 属性
【发布时间】:2013-12-04 14:23:02
【问题描述】:

我为我的所有实体添加了一个 lastModifiedDate 属性,以避免在将 UIManagedDocument 与 iCloud 同步时出现重复,我发现如果我使用离线设备 (iPad) 创建新实体可能会发生这种情况同时,我使用另一个在线设备(iPhone)创建了相同的实体。

我想在对象更改时设置此属性,因此我订阅了NSManagedObjectContextObjectsDidChangeNotification。我编写的用于设置 lastModifiedDate 的代码会创建一个无限循环,因为通过设置 lastModificationDate 属性它会创建一个更改,该更改将由 NSManagedObjectContextObjectsDidChangeNotification 等再次通知...

有办法解决吗?有没有更好的方法来实现我的目标?我应该继承 managedObjectContext 并覆盖willSave:吗?

//At init...

[[NSNotificationCenter defaultCenter] addObserver:applicationDatabase
                                             selector:@selector(objectsDidChange:)
                                                 name:NSManagedObjectContextObjectsDidChangeNotification
                                               object:applicationDatabase.managedDocument.managedObjectContext];


(void) objectsDidChange: (NSNotification*) note
{
  // creates an infinite loop
    NSDate *dateOfTheLastModification = [NSDate date];
    NSMutableArray *userInfoKeys = [[note.userInfo allKeys] mutableCopy];

    for(int i=0; i< userInfoKeys.count;i++){
        NSString *key = [userInfoKeys objectAtIndex:i];
        if([key isEqualToString:@"managedObjectContext"]){
            [userInfoKeys removeObject:key];
        }
    }

    for(NSString *key in userInfoKeys){
        NSArray *detail = [note.userInfo objectForKey:key];
        for (id object in detail){

            [object setValue:dateOfTheLastModification forKey:@"lastModifiedDate"];
        }
}

【问题讨论】:

    标签: ios objective-c core-data icloud uimanageddocument


    【解决方案1】:

    为避免无限循环,您可以使用 原始访问器

    [object setPrimitiveValue:dateOfTheLastModification forKey:@"lastModifiedDate"];
    

    因为这不会触发另一个“更改”通知。但这也意味着 没有观察者会看到这种变化。

    在托管对象子类中覆盖willSave 会遇到同样的问题。 willSave 的 Apple 文档指出:

    例如,如果您设置了最后修改的时间戳,您应该检查 您之前是否在相同的保存操作中设置它,或者 现有的时间戳不小于与 当前时间。通常最好计算一次时间戳 对于所有正在保存的对象(例如,响应 NSManagedObjectContextWillSaveNotification)。

    所以你应该注册NSManagedObjectContextWillSaveNotification, 并为托管对象中所有更新和插入的对象设置时间戳 语境。注册的方法可能如下所示:

    -(void)contextWillSave:(NSNotification *)notify
    {
        NSManagedObjectContext *context = [notify object];
        NSDate *dateOfTheLastModification = [NSDate date];
        for (NSManagedObject *obj in [context insertedObjects]) {
            [obj setValue:dateOfTheLastModification forKey:@"lastModifiedDate"];
        }
        for (NSManagedObject *obj in [context updatedObjects]) {
            [obj setValue:dateOfTheLastModification forKey:@"lastModifiedDate"];
        }
    }
    

    这假定您的所有实体都具有lastModifiedDate 属性,否则 您必须检查对象的类别。

    【讨论】:

    • 我为此在 SO 上找到了一堆不同的问题/解决方案,但这是 A)唯一有效的问题和 B)唯一一个答案比“使用 NSManagedObjectContextWillSaveNotification”更详细的问题。 :-P 谢谢!
    • WillSave 通知适用于时间戳,但会说手动级联某些东西,例如说一个“垃圾”属性,您想将其级联到所有相关对象。您应该在 DidChange 中执行此操作,例如 UI 可以在保存之前更新,还是应该在 WillSave 中以相同的方式完成?
    猜你喜欢
    • 2013-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    • 2021-08-11
    • 1970-01-01
    • 2013-12-24
    • 2015-01-24
    相关资源
    最近更新 更多