@synthesize vs @dynamic, ¿cuáles son las diferencias?

Respuestas:

744

@synthesize generará métodos getter y setter para su propiedad. @dynamic solo le dice al compilador que los métodos getter y setter no son implementados por la clase en sí sino en otro lugar (como la superclase o se proporcionarán en tiempo de ejecución).

Los usos de @dynamic son, por ejemplo, con subclases de NSManagedObject(CoreData) o cuando desea crear una salida para una propiedad definida por una superclase que no se definió como una salida.

@dynamic también se puede usar para delegar la responsabilidad de implementar los accesos. Si implementa los accesores usted mismo dentro de la clase, normalmente no usa @dynamic.

Super clase:

@property (nonatomic, retain) NSButton *someButton;
...
@synthesize someButton;

Subclase:

@property (nonatomic, retain) IBOutlet NSButton *someButton;
...
@dynamic someButton;
diederikh
fuente
25
no 100% correcto; dinámico es el valor predeterminado si no configura @synthesize o @dynamic. especificar @dynamic simplemente significa que usted asume la responsabilidad de implementar correctamente los accesores de propiedad en función de la firma de la declaración de propiedad.
Kevlar
68
En realidad no, @dynamic significa que se delega la responsabilidad de implementar los accesos. Si implementa los accesores usted mismo dentro de la clase, normalmente no usa @dynamic.
diederikh
2
Obtuve NSUnknownKeyExceptionerrores con mi propiedad dinámica cuando eliminé la @synthesizelínea (Xcode 3.2 me estaba dando un error b / c no tenía ivar coincidente para mi @property). Agregar @dynamicsolucionó el problema: compila y funciona bien ahora. ¡Gracias!
pix0r
44
Lo sentimos, comprar esto está completamente mal. @dynamic dice que los accesores se resuelven en tiempo de ejecución, a menos que se declaren en la clase o superclase (no en otro lugar). Puede leer la documentación developer.apple.com/library/mac/documentation/cocoa/conceptual/…
user1447414
55
Kevlar: no. En el ObjC moderno, los @propertyelementos que no tienen @synthesizeni @dynamicse sintetizarán automáticamente. Para cada propiedad, se creará un ivar con un guión bajo, por ejemplo _propertyName, junto con el captador y definidor apropiado.
Dave R
212

Echa un vistazo a este artículo ; bajo el título "Métodos proporcionados en tiempo de ejecución":

Algunos accesos se crean dinámicamente en tiempo de ejecución, como algunos utilizados en la clase NSManagedObject de CoreData. Si desea declarar y usar propiedades para estos casos, pero quiere evitar advertencias sobre los métodos que faltan en el momento de la compilación, puede usar la directiva @dynamic en lugar de @synthesize.

...

El uso de la directiva @dynamic esencialmente le dice al compilador "no te preocupes por eso, un método está en camino".

La @synthesizedirectiva, por otro lado, genera los métodos de acceso para usted en el momento de la compilación (aunque, como se señaló en la sección "Mezcla de accesores sintetizados y personalizados", es flexible y no genera métodos para usted si se implementan).

Alex Rozanski
fuente
27
Este es el hombre más corrector. Esta respuesta es la única respuesta que se habla de métodos creados en tiempo de ejecución, lo que realmente parece captar el espíritu mucho más de lo más votadas ans atm
bobobobo
30

Como han dicho otros, en general usa @synthesize para que el compilador genere los captadores y / o configuraciones para usted, y @dynamic si va a escribirlos usted mismo.

Hay otra sutileza aún no mencionada: @synthesize le permitirá proporcionar una implementación usted mismo, ya sea de un getter o un setter. Esto es útil si solo desea implementar el getter para obtener una lógica adicional, pero permite que el compilador genere el setter (que, para los objetos, generalmente es un poco más complejo de escribir usted mismo).

Sin embargo, si escribe una implementación para un descriptor de acceso @ sintetizado, aún debe estar respaldado por un campo real (por ejemplo, si escribe -(int) getFoo();debe tener un int foo;campo). Si el valor está siendo producido por otra cosa (por ejemplo, calculado a partir de otros campos), entonces debe usar @dynamic.

philsquared
fuente
2
+1 para mencionar una diferencia importante: @dynamic te permite crear accesores para objetos no definidos en la interfaz de tu clase y a través de la introspección.
mahboudz el
24
"y @dynamicsi vas a escribirlos tú mismo" No, NO utilizas dinámico si los escribes tú mismo. @dynamicapaga la comprobación del compilador para asegurarse de que los implementó. Si los implementó usted mismo, desea que el compilador verifique.
user102008
14

@dynamic se usa típicamente (como se ha dicho anteriormente) cuando una propiedad se crea dinámicamente en tiempo de ejecución. NSManagedObject hace esto (por qué todas sus propiedades son dinámicas), lo que suprime algunas advertencias del compilador.

Para obtener una buena descripción general sobre cómo crear propiedades dinámicamente (sin NSManagedObject y CoreData :, consulte: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#// apple_ref / doc / uid / TP40008048-CH102-SW1

mifortina
fuente
14

Aquí hay un ejemplo de @dynamic

#import <Foundation/Foundation.h>

@interface Book : NSObject
{
   NSMutableDictionary *data;
}
@property (retain) NSString *title;
@property (retain) NSString *author;
@end

@implementation Book
@dynamic title, author;

- (id)init
{
    if ((self = [super init])) {
        data = [[NSMutableDictionary alloc] init];
        [data setObject:@"Tom Sawyer" forKey:@"title"];
        [data setObject:@"Mark Twain" forKey:@"author"];
    }
    return self;
}

- (void)dealloc
{
    [data release];
    [super dealloc];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    NSString *sel = NSStringFromSelector(selector);
    if ([sel rangeOfString:@"set"].location == 0) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    } else {
        return [NSMethodSignature signatureWithObjCTypes:"@@:"];
    }
 }

- (void)forwardInvocation:(NSInvocation *)invocation
{
    NSString *key = NSStringFromSelector([invocation selector]);
    if ([key rangeOfString:@"set"].location == 0) {
        key = [[key substringWithRange:NSMakeRange(3, [key length]-4)] lowercaseString];
        NSString *obj;
        [invocation getArgument:&obj atIndex:2];
        [data setObject:obj forKey:key];
    } else {
        NSString *obj = [data objectForKey:key];
        [invocation setReturnValue:&obj];
    }
}

@end

int main(int argc, char **argv)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Book *book = [[Book alloc] init];
    printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);
    book.title = @"1984";
    book.author = @"George Orwell";
    printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);

   [book release];
   [pool release];
   return 0;
}
espejo
fuente
10

Según la documentación:

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html

@dynamic le dice al compilador que los métodos de acceso se proporcionan en tiempo de ejecución.

Con un poco de investigación descubrí que proporcionar métodos de acceso anula la directiva @dynamic.

@synthesize le dice al compilador que cree esos accesores para usted (getter y setter)

@property le dice al compilador que se crearán los accesos, y que se puede acceder con la notación de punto o [mensaje de objeto]

usuario1447414
fuente
6

Una cosa que quiero agregar es que si una propiedad se declara como @dynamic, no ocupará memoria (confirme con el instrumento de asignación). Una consecuencia es que puede declarar propiedades en la categoría de clase.

Yingpei Zeng
fuente
Si anulo un establecedor de propiedad en una categoría y lo hago dinámico, ¿esto garantizará que el reemplazo se utilizará en tiempo de ejecución y no el configurador de la clase principal? De los documentos de Apple: "Si el nombre de un método declarado en una categoría es el mismo que el de un método en la clase original ... el comportamiento no está definido en cuanto a qué implementación de método se utiliza en tiempo de ejecución".
David James
No, creo que el comportamiento aún no está definido. Hacer que la propiedad en la categoría sea dinámica no cambia la prioridad de tiempo de ejecución del método de establecimiento de propiedades.
Yingpei Zeng el
3

Según la documentación de Apple.

Utiliza la @synthesizeinstrucción en el bloque de implementación de una clase para indicarle al compilador que cree implementaciones que coincidan con la especificación que proporcionó en la @propertydeclaración.

Utiliza la @dynamicinstrucción para indicarle al compilador que suprima una advertencia si no puede encontrar una implementación de métodos de acceso especificados por una @propertydeclaración.

Más información:-

https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/DeclaredProperty.html

arango_86
fuente