【问题标题】:KVO addObserver to CoreData object's one-to-many relationshipKVO addObserver 到 CoreData 对象的一对多关系
【发布时间】:2013-03-27 12:14:04
【问题描述】:

大家好,多年阅读 StackOverflow,现在我决定加入。我正在努力解决这个问题:

我有一个“仓库”实体,它有两个对多的关系“人员”和“卡车”。我想观察在给定“仓库”对象的情况下,其中一种关系发生变化(插入、删除)(并了解是哪一种)。

目前我正在这样做:

[mydepot addObserver:self forKeyPath:@"Trucks" options:NSKeyValueObservingOptionNew context:nil];

[mydepot addObserver:self forKeyPath:@"Persons" options:NSKeyValueObservingOptionNew context:nil];

但每当两个相关集合之一发生变化时,observeValueForKeyPath 就会被调用两次(每个键路径一次)。

我做错了吗?查看“更改”字典,(也观察 OptionOld)显示没有意外更改(当我更换人员时,卡车没有更改),但仍然会发出通知。

谢谢,彼得罗

编辑:似乎两次“更改”字典都包含“新”字段中的整个关系。 (显然一次是人,一次是卡车)

edit2:即使是简单的属性,它也会与 managedctx 保存操作有关吗?好像保存时,整个对象都被认为已更改..

【问题讨论】:

    标签: ios objective-c core-data key-value-observing


    【解决方案1】:

    在 Key Value Observing Programming Guide 中说

    如果您使用 Core Data,您可以将父级注册到应用程序的通知中心,作为其托管对象上下文的观察者。父级应以类似于键值观察的方式响应子级发布的相关更改通知。

    这实际上意味着建议的做法不是使用addObserver:forKeyPath:options:context:,而是注册NSManagedObjectContextDidSaveNotification

    【讨论】:

    • 是的,这是我的第二选择,因为我一次只想要观察一个对象(但可以在后台修改多个对象),我认为这是浪费通知当我收到所有更改对象的通知时,必须过滤掉通知
    • @Peterdeka 这仍然是最好和正确的答案。你应该接受它。
    【解决方案2】:

    如果您以原子方式设置卡车 (something.trucks = newArray),您将收到值设置通知。而是在 [ something mutableArrayValueForKey:@"trucks" ] 返回的可变数组上使用 addObject/removeObject。

    您还可以使用/实现 KVO 生成的访问器 insertObjectIntoTrucks: / countOfTrucks 等。

    您应该阅读 KVO 文档。在“索引对多关系合规性”和“无序对多关系合规性”here 下。

    【讨论】:

    • +1 同意。考虑修改现有的值集合,而不是用不同的集合替换整个集合。
    • 谢谢,是的,但是 Depot 是一个 CoreData NSManagedObject 子类,所以应该已经实现了符合 KVO 的访问器。我正在做你所说的,事实上我只是在关系中添加一个新的卡车实体,从不替换/设置整个集合(关系)。这就是为什么我无法理解。好像我观察到两个关键路径,例如“卡车”和“平方米”(这不是关系),如果“平方米”被修改,则会触发两个通知(也是一个用于“卡车”kpath)
    • 关键路径可以相互依赖...也许这就是正在发生的事情?否则你将不得不寻找其他地方
    • 模型很简单,所以看起来它们之间没有任何关系......不会是与托管上下文保存操作有关吗?好像保存会触发新集合的创建,如果它们被修改(对象的重新分配排序)?
    • 请注意,对象正在后台在不同的“便签本”mangedobjectcontext 上进行修改,然后合并更改
    【解决方案3】:

    我遇到了同样的问题。我仍然坚持这个问题。

    但我可以肯定的是,第一次调用它的原因是您执行类似[Depot addPerson:person] 之类的操作,而第二次调用它的原因是 MOC 保存操作将发布 NSManagedObjectContextDidSaveNotification 通知这让你的观察者认为另一个修改刚刚发生。

    我的问题更糟糕的是,因为观察者,我会丢失一些我对核心数据的修改。

    这让我觉得自己蠢了将近两天。

    我正在考虑在@Mundi 的回答中使用寄存器NSManagedObjectContextDidSaveNotification

    如果有人有更好的方法,请尽快告诉我

    【讨论】:

      【解决方案4】:

      我保留了一些缓存作为 NSManagedObject 的属性,并且需要使它们无效。我首先研究了使用 KVO 并收听了NSManagedObjectContextDidSaveNotification

      对我来说最简单的解决方案是像这样实现 – [NSManagedObject didSave]– [NSManagedObject didTurnIntoFault] 方法。

      @interface BazClass ()
      @property (nonatomic, strong) NSArray* sortedItems;    // sorted items cache
      @end
      
      @implementation BazClass
      
      @dynamic items; // this is a to many relationship. i.e. NSOrderedSet
      @synthesize sortedItems;
      
      - (NSArray*)sortedItems
      {
          if (!_sortedItems) {
              NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"foo" ascending:YES];
              _sortedItems = [self.items sortedArrayUsingDescriptors:@[sortDescriptor]];
          }
          return _sortedItems;
      }
      
      // didSave and didTurnIntoFault will delete the sorted items cache
      - (void) didSave
      {
          self.sortedItems = nil;
      }
      
      -(void) didTurnIntoFault
      {
          self. sortedItems = nil;
      }
      

      【讨论】:

        【解决方案5】:

        如果您想知道何时从一对多卡车关系中添加或删除项目,您需要对计数(在您的视图控制器中的某处)执行 KVO,如下所示:

        [self.depot addObserver:self forKeyPath:@"trucks.@count" options:0 context:nil];

        【讨论】:

          猜你喜欢
          • 2012-01-10
          • 1970-01-01
          • 1970-01-01
          • 2014-07-19
          • 1970-01-01
          • 1970-01-01
          • 2014-04-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多