1

I got few entities for an iOS App which are linked by relations. To make a simple example, lets assume we got a relation like this (one-to-many):

company <--->> person

I'm using xcode 4.6 and the core data modelling tool for model generation, so I end up with

//Company.h
@class Person;
@interface Company : NSManagedObject
@property (nonatomic, retain) NSString * company_name;
@property (nonatomic, retain) NSNumber *has_changed;
@property (nonatomic, retain) NSSet *person;
@end

@interface Company (CoreDataGeneratedAccessors)
- (void)addPersonObject:(Person *)value;
- (void)removePersonObject:(Person *)value;
- (void)addPerson:(NSSet *)values;
- (void)removePerson:(NSSet *)values;
@end

//Company.m
#import "Company.h"
#import "Person.h"

@implementation Company
@dynamic company_name;
@dynamic has_changed;
@dynamic person;
@end

And

//Person.h
@class Company;

@interface Person : NSManagedObject
@property (nonatomic, retain) NSString * first_name;
@property (nonatomic, retain) NSString * last_name;
@property (nonatomic, retain) Company *company;
@end

//Person.m
#import "Person.h"
#import "Company.h"

@implementation Person
@dynamic first_name;
@dynamic last_name;
@dynamic company;
@end

Now, suppose I want to set the boolean (implemented as NSNumber in Core Data) attribute has_changed to TRUE every time one of the following occurs:

  • a attribute of the company entity is changed, except the has_changed attribute itself of course (since this would cause a loop)
  • a attribute of the person entity is changed

What would be the best (easy to implement + fast to process) way to implement something like this? For what I was able to find out, is that there are two options:

However, everything I find related to this topic seems to be outdated because of the changes in objective-c 2.0, core-data / cocoa or iOS. For example, automatically generating the accessor methods by using the core-data modelling editor dosn't seem to work when using xcode 4.6 with ARC enabled, since everything I get pasted are the @dynamic lines which core-data generates anyways (see code example above).

Also I find it a bit confusing what the documentation says. What would be the best way to implement this? KVO? Custom accessors? Bit of both or even something compleatly different? And how would a possible implementation look like for the given example?

omni
  • 4,104
  • 8
  • 48
  • 67
  • What have you found that indicates that KVO is outdated? – Wain Aug 18 '13 at 21:43
  • Not KVO in general, but in special when used within entity classes. What I mean is that I'm not sure what's the "right" way to do it and where to place the KVO implementation: within the entity? Within a service/controller class? Or better use custom accessor methods within the entity? What about the child entity: should I use a observer looking for the parent entity there or should I write custom accessors and within them manipulate the parents has_changed attribute? – omni Aug 18 '13 at 21:54
  • Good question, but a duplicate of: [How do you determine if an object (self) with a lot of properties has been changed?](http://stackoverflow.com/questions/11398684/how-do-you-determine-if-an-object-self-with-a-lot-of-properties-has-been-chang) – lnafziger Aug 18 '13 at 21:56
  • @Inafziger the example you linked to dosn't use ARC nor core-data. I agree that it might be a good general answer about KVO, but my question is not about KVO but about if KVO or custom core-data accessor methods or a combination of both is the way to go for the given example. – omni Aug 18 '13 at 22:08

1 Answers1

1

You could do this as such:

@implementation Company
// ...

- (void) didChangeValueForKey: (NSString *) key
{ 
   [super didChangeValueForKey: key];
   if (! [key isEqualToString: @"has_changed"])
     self.has_changed = YES;
}

// ...
@end

and similar for Person though the company property. You'd also want to implement didChangeValueForKey:withSetMutation:usingObjects:

Note that this suggestion does not address the common need of having a controller know about a change. There are other ways to do that.

GoZoner
  • 67,920
  • 20
  • 95
  • 145
  • Will this somehow "disable" the automatic setters/getters or anything else created by core-data? Are there any other things I will have to take care about when I create a custom `didChangeValueForKey` method? – omni Aug 18 '13 at 21:57
  • Edited to add in the 'super' call. – GoZoner Aug 18 '13 at 22:02
  • Hmm okay now this looks nice. But I don't get your note: how does core-data handle the controller notification or does it handle it (if automatically generated as in the given example above) at all? – omni Aug 18 '13 at 22:04
  • 1
    See `NSFetchedResultsControllerDelegate` (if you are using a `NSFetchedResultsController`) or the notification methods on NSManagedObjectContext. Also, note that there is a hasChanges boolean already on NSManagedObject but that it has a slightly different meaning from what you have asked. – GoZoner Aug 18 '13 at 22:14
  • Currently I'm not using a NSFetchedResultsController but only NSManagedObjectContext. I'm aware of the fact that IF I want my view to get updated I have to implement some kind of notification. Now the relevant part for this question would be: if I override the didChangeValueForKey method, would I have to do anything different to implement the notification than I would if i would not override the method? I guess the quick answer is "no"? – omni Aug 18 '13 at 22:33