Пользовательские методы установки в Core-Data - PullRequest
67 голосов
/ 04 июня 2010

Мне нужно написать собственный метод установки для поля (назовем его foo) в моем подклассе NSManagedObject. foo определено в модели данных, и Xcode автоматически сгенерировал поля @property и @dynamic в файлах .h и .m соответственно.

Если я напишу свой сеттер так:

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

тогда я получаю предупреждение компилятора при вызове super.

В качестве альтернативы, если я сделаю это:

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

тогда я оказываюсь в бесконечном цикле.

Так каков правильный подход к написанию пользовательского сеттера для подкласса NSManagedObject?

Ответы [ 5 ]

102 голосов
/ 04 июня 2010

Согласно документации , это будет:

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

Это, конечно, игнорирование того факта, что NSManagedObjects хочет только NSNumbers, NSDates, NSDatas и NSStrings в качестве атрибутов.

Однако это может быть не лучшим подходом. Поскольку вы хотите, чтобы что-то происходило при изменении значения вашего свойства foo, почему бы просто не наблюдать это с помощью Наблюдение значения ключа ? В этом случае это звучит как «КВО - это путь».

19 голосов
/ 26 апреля 2011

Вот как я делаю КВО для атрибута id для Photo : NSManagedObject. Если идентификатор фотографии изменится, загрузите новую фотографию.

#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
}
17 голосов
/ 04 июня 2010

Я думаю, что есть небольшая ошибка: используйте

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

вместо

 [self setPrimitiveFoo:inFoo];

это работает для меня.

7 голосов
/ 23 февраля 2018

Вот способ Apple для переопределения свойств NSManagedObject (без нарушения KVO) в вашем .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 - это встроенный метод magic , для которого нужно просто добавить определение. Как видно внизу этой страницы Что нового в Core Data в macOS 10.12, iOS 10.0, tvOS 10.0 и watchOS 3.0

0 голосов
/ 15 апреля 2016

Вот как вы делаете это 1-n (и я предполагаю, что n-m) отношений:

Предположим, что имя отношения называется "ученики" в объекте "Школа".

Сначала вам нужно определить примитивные методы доступа для NSMutableSet. XCode не будет автоматически генерировать их для вас.

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

Далее вы можете определить свой метод доступа. Здесь я собираюсь переопределить сеттер.

- (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];
}
...