Métodos de configuración personalizados en Core-Data


Necesito escribir un método setter personalizado para un campo (lo llamaremos foo) en mi subclase de NSManagedObject. foo se define en el modelo de datos y Xcode ha autogenerado @property y @dynamic campos en el.h y .m archivos, respectivamente.

Si escribo mi setter así:

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

Entonces recibo una advertencia del compilador sobre la llamada a super.

Alternativamente, si hago esto:

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

Entonces termino en un bucle infinito.

Entonces, ¿cuál es el enfoque correcto para escribir un personalizado setter para una subclase de NSManagedObject?

Author: Andrew Ebling, 2010-06-04

5 answers

Aquí está la forma de Apple para sobreescribir las propiedades NSManagedObject (sin romper KVO), en su .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 es un método incorporado magic que solo tiene que agregar la definición para. Como se ve en la parte inferior de esta página Qué hay de nuevo en Core Data en macOS 10.12, iOS 10.0, tvOS 10.0 y watchOS 3.0

 3
Author: malhal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-23 14:01:48

De acuerdo con la documentación , sería:

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

Esto es, por supuesto, ignorando el hecho de que NSManagedObjects sólo quieren NSNumbers, NSDates, NSDatas, y NSStrings como atributos.

Sin embargo, este podría no ser el mejor enfoque. Ya que desea que algo suceda cuando el valor de su propiedad foo cambia, ¿por qué no simplemente observarlo con Key Value Observando? En este caso, suena como "KVO es el camino a seguir".

 100
Author: Dave DeLong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-19 01:12:29

Así es como estoy haciendo KVO en el atributo id de a Photo : NSManagedObject. Si el ID de la foto cambia, descarga la nueva foto.

#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
}
 19
Author: ma11hew28,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-26 13:26:58

Creo que hay un pequeño error: use

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

En lugar de

 [self setPrimitiveFoo:inFoo];

Esto funciona para mí.

 17
Author: Martin Brugger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-04 06:32:53

Así es como lo haces 1-n (y supongo que n-m) relaciones:

Supongamos que el nombre de la relación se llama "estudiantes" en un objeto llamado "Escuela".

Primero debe definir los métodos de acceso primitivos para el conjunto NSMutableSet. Xcode no generará automáticamente estos para usted.

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

A continuación puede definir su método de acceso. Aquí voy a anular el 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];
}
 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-14 23:24:57