@synthesize vs @dynamic, quelles sont les différences?

Réponses:

744

@synthesize générera des méthodes getter et setter pour votre propriété. @dynamic indique simplement au compilateur que les méthodes getter et setter ne sont pas implémentées par la classe elle-même mais ailleurs (comme la superclasse ou seront fournies lors de l'exécution).

Les utilisations de @dynamic sont par exemple avec des sous-classes de NSManagedObject(CoreData) ou lorsque vous souhaitez créer une sortie pour une propriété définie par une superclasse qui n'a pas été définie comme sortie.

@dynamic peut également être utilisé pour déléguer la responsabilité de la mise en œuvre des accesseurs. Si vous implémentez les accesseurs vous-même dans la classe, vous n'utilisez normalement pas @dynamic.

Super classe:

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

Sous-classe:

@property (nonatomic, retain) IBOutlet NSButton *someButton;
...
@dynamic someButton;
deaderikh
la source
25
pas 100% à droite; dynamique est la valeur par défaut si vous ne définissez ni @synthesize ni @dynamic. la spécification de @dynamic signifie simplement que vous êtes responsable de la bonne mise en œuvre des accesseurs de propriété sur la base de la signature de la déclaration de propriété.
Kevlar
68
Pas vraiment, @dynamic signifie que la responsabilité de la mise en œuvre des accesseurs est déléguée. Si vous implémentez les accesseurs vous-même dans la classe, vous n'utilisez normalement pas @dynamic.
deaderikh
2
J'obtenais des NSUnknownKeyExceptionerreurs avec ma propriété dynamique lorsque j'ai supprimé la @synthesizeligne (Xcode 3.2 me donnait une erreur b / c je n'avais pas d'ivar correspondant pour mon @property). L'ajout a @dynamicrésolu le problème - se compile et fonctionne bien maintenant. Merci!
pix0r
4
Désolé, acheter ceci est tout à fait faux. @dynamic indique que les accesseurs sont résolus au moment de l'exécution, à moins qu'ils ne soient déclarés dans la classe ou la superclasse (pas ailleurs). Vous pouvez lire la documentation developer.apple.com/library/mac/documentation/cocoa/conceptual/…
user1447414
5
Kevlar: non. Dans ObjC moderne, les @propertyéléments qui n'ont ni @synthesizene @dynamicseront synthétisés automatiquement. Pour chaque propriété, un ivar avec un soulignement de tête, par exemple, _propertyNamesera créé, avec le getter et le setter appropriés.
Dave R
212

Jetez un oeil à cet article ; sous la rubrique "Méthodes fournies lors de l'exécution":

Certains accesseurs sont créés dynamiquement au moment de l'exécution, tels que certains utilisés dans la classe NSManagedObject de CoreData. Si vous souhaitez déclarer et utiliser des propriétés pour ces cas, mais que vous souhaitez éviter les avertissements concernant les méthodes manquantes au moment de la compilation, vous pouvez utiliser la directive @dynamic au lieu de @synthesize.

...

L'utilisation de la directive @dynamic indique essentiellement au compilateur "ne vous en faites pas, une méthode est en cours".

La @synthesizedirective, d'autre part, génère les méthodes d'accesseur pour vous au moment de la compilation (bien que comme indiqué dans la section "Mixage des accesseurs synthétisés et personnalisés", elle est flexible et ne génère pas de méthodes pour vous si l'une ou l'autre est implémentée).

Alex Rozanski
la source
27
C'est un homme plus correct. Cette réponse est la seule réponse qui parle de méthodes créées lors de l'exécution, ce qui semble vraiment capturer l'esprit beaucoup plus que le meilleur vote et atm
bobobobo
30

Comme d'autres l'ont dit, en général, vous utilisez @synthesize pour que le compilateur génère les getters et / ou les paramètres pour vous, et @dynamic si vous allez les écrire vous-même.

Il y a une autre subtilité pas encore mentionné: @synthesize va vous permettre de fournir une implémentation vous, soit d' un getter ou un setter. Ceci est utile si vous souhaitez uniquement implémenter le getter pour une logique supplémentaire, mais laissez le compilateur générer le setter (qui, pour les objets, est généralement un peu plus complexe à écrire vous-même).

Cependant, si vous écrivez une implémentation pour un accesseur @ synthétisé, elle doit toujours être soutenue par un champ réel (par exemple, si vous écrivez, -(int) getFoo();vous devez avoir un int foo;champ). Si la valeur est produite par autre chose (par exemple calculée à partir d'autres champs), vous devez utiliser @dynamic.

philsquared
la source
2
+1 pour mentionner une différence importante: @dynamic vous permet de créer des accesseurs pour les variables non définies dans votre interface de classe et par introspection.
mahboudz
24
"et @dynamicsi vous allez les écrire vous-même" Non, vous n'utilisez PAS dynamique si vous les écrivez vous-même. @dynamicdésactive la vérification du compilateur pour vous assurer que vous les avez implémentés. Si vous les avez implémentés vous-même, vous voulez que le compilateur vérifie.
user102008
14

@dynamic est généralement utilisé (comme cela a été dit ci-dessus) lorsqu'une propriété est créée dynamiquement au moment de l'exécution. NSManagedObject le fait (pourquoi toutes ses propriétés sont dynamiques) - ce qui supprime certains avertissements du compilateur.

Pour une bonne vue d'ensemble sur la façon de créer des propriétés dynamiquement (sans NSManagedObject et CoreData:, voir: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#// apple_ref / doc / uid / TP40008048-CH102-SW1

mifortine
la source
14

voici un exemple 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;
}
miroir
la source
10

Selon la documentation:

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

@dynamic indique au compilateur que les méthodes d'accesseur sont fournies au moment de l'exécution.

Avec un peu d'investigation, j'ai découvert que la fourniture de méthodes d'accesseur remplaçait la directive @dynamic.

@synthesize dit au compilateur de créer ces accesseurs pour vous (getter et setter)

@property indique au compilateur que les accesseurs seront créés, et que l'on peut y accéder avec la notation par points ou [message d'objet]

user1447414
la source
6

Une chose à ajouter est que si une propriété est déclarée comme @dynamic, elle n'occupera pas de mémoire (j'ai confirmé avec l'instrument d'allocation). Une conséquence est que vous pouvez déclarer une propriété dans la catégorie de classe.

Yingpei Zeng
la source
Si je remplace un setter de propriété dans une catégorie et le rend dynamique, cela garantira-t-il que le override sera utilisé lors de l'exécution et non le setter de la classe parent? D'après Apple docs: "Si le nom d'une méthode déclarée dans une catégorie est identique à une méthode de la classe d'origine ... le comportement n'est pas défini quant à l'implémentation de la méthode utilisée lors de l'exécution."
David James
Non, je pense que le comportement n'est pas encore défini. La dynamisation de la propriété de la catégorie ne modifie pas la priorité d'exécution de la méthode de définition des propriétés.
Yingpei Zeng
3

Selon la documentation Apple.

Vous utilisez l' @synthesizeinstruction dans le bloc d'implémentation d'une classe pour indiquer au compilateur de créer des implémentations qui correspondent à la spécification que vous avez donnée dans la @propertydéclaration.

Vous utilisez l' @dynamicinstruction pour indiquer au compilateur de supprimer un avertissement s'il ne trouve pas une implémentation des méthodes d'accesseur spécifiées par une @propertydéclaration.

Plus d'informations:-

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

arango_86
la source