Custom setter methods in Core-Data

旧时模样 提交于 2020-01-19 06:49:09

问题


I need to write a custom setter method for a field (we'll call it foo) in my subclass of NSManagedObject. foo is defined in the data model and Xcode has autogenerated @property and @dynamic fields in the .h and .m files respectively.

If I write my setter like this:

- (void)setFoo: (NSObject *)inFoo {
    [super setFoo: inFoo];
    [self updateStuff];
}

then I get a compiler warning on the call to super.

Alternatively, if I do this:

- (void)setFoo: (NSObject *)inFoo {
    [super setValue: inFoo forKey: inFoo];
    [self updateStuff];
}

then I end up in an infinite loop.

So what's the correct approach to write a custom setter for a subclass of NSManagedObject?


回答1:


Here is the Apple way for overriding NSManagedObject properties (without breaking KVO), in your .m:

@interface Transaction (DynamicAccessors)
- (void)managedObjectOriginal_setDate:(NSDate *)date;
@end

@implementation Transaction
@dynamic date;

- (void)setDate:(NSDate *)date
{
    // invoke the dynamic implementation of setDate (calls the willChange/didChange for you)
    [self managedObjectOriginal_setDate:(NSString *)date;

    // your custom code
}

managedObjectOriginal_propertyName is a built-in magic method you just have to add the definition for. As seen at bottom of this page What's New in Core Data in macOS 10.12, iOS 10.0, tvOS 10.0, and watchOS 3.0




回答2:


According to the documentation, it'd be:

- (void) setFoo:(NSObject *)inFoo {
  [self willChangeValueForKey:@"foo"];
  [self setPrimitiveValue:inFoo forKey:@"foo"];
  [self didChangeValueForKey:@"foo"];
}

This is, of course, ignoring the fact that NSManagedObjects only want NSNumbers, NSDates, NSDatas, and NSStrings as attributes.

However, this might not be the best approach. Since you want something to happen when the value of your foo property changes, why not just observe it with Key Value Observing? In this case, it sounds like "KVO's the way to go".




回答3:


Here's how I'm doing KVO on the id attribute of a Photo : NSManagedObject. If the photo's ID changes, then download the new photo.

#pragma mark NSManagedObject

- (void)awakeFromInsert {
    [self observePhotoId];
}

- (void)awakeFromFetch {
    [self observePhotoId];
}

- (void)observePhotoId {
    [self addObserver:self forKeyPath:@"id"
              options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change
                       context:(void *)context {
    if ([keyPath isEqualToString:@"id"]) {
        NSString *oldValue = [change objectForKey:NSKeyValueChangeOldKey];
        NSString *newValue = [change objectForKey:NSKeyValueChangeNewKey];        
        if (![newValue isEqualToString:oldValue]) {
            [self handleIdChange];
        }
    }
}

- (void)willTurnIntoFault {
    [self removeObserver:self forKeyPath:@"id"];
}

#pragma mark Photo

- (void)handleIdChange {
    // Implemented by subclasses, but defined here to hide warnings.
    // [self download]; // example implementation
}



回答4:


I think there is a slight mistake: use

 [self setPrimitiveValue:inFoo forKey:@"foo"];

instead of

 [self setPrimitiveFoo:inFoo];

this works for me.




回答5:


Here's how you do it 1-n (and I presume n-m) relationships:

Lets assume the relationship name is called "students" in an object called "School".

First you need to define the primitive accessor methods for the NSMutableSet. Xcode will not automatically generate these for you.

@interface School(PrimitiveAccessors)
- (NSMutableSet *)primitiveStudents;
@end

Next you can define your accessor method. Here I'm going to override the setter.

- (void)addStudentsObject:(Student *)student
{
  NSSet *changedObjects = [[NSSet alloc] initWithObjects:&student count:1];

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

  [[self primitiveStudents] addObject:value];

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


来源:https://stackoverflow.com/questions/2971806/custom-setter-methods-in-core-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!