@synthesize vs @dynamic, quali sono le differenze?


Risposte:


744

@synthesize genererà metodi getter e setter per la tua proprietà. @dynamic dice al compilatore che i metodi getter e setter non sono implementati dalla classe stessa ma da qualche altra parte (come la superclasse o saranno forniti in fase di esecuzione).

Gli usi di @dynamic sono ad es. Con sottoclassi di NSManagedObject(CoreData) o quando si desidera creare un outlet per una proprietà definita da una superclasse che non è stata definita come outlet.

@dynamic può anche essere usato per delegare la responsabilità dell'implementazione degli accessor. Se implementi tu stesso gli accessori all'interno della classe, normalmente non usi @dynamic.

Classe eccellente:

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

sottoclasse:

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

25
non giusto al 100%; dinamico è l'impostazione predefinita se non si imposta @synthesize o @dynamic. specificare @dynamic significa semplicemente che ti assumi la responsabilità di implementare correttamente gli accessori di proprietà in base alla firma della dichiarazione di proprietà.
Kevlar,

68
Non proprio, @dynamic significa delegare la responsabilità dell'implementazione degli accessori. Se implementi tu stesso gli accessori all'interno della classe, normalmente non usi @dynamic.
diederikh,

2
Stavo ricevendo NSUnknownKeyExceptionerrori con la mia proprietà dinamica quando ho rimosso la @synthesizeriga (Xcode 3.2 mi stava dando un errore b / c non avevo ivar corrispondente per la mia proprietà @). L'aggiunta ha @dynamicrisolto il problema: ora viene compilata ed eseguita correttamente. Grazie!
pix0r,

4
Spiacenti, acquista questo è completamente sbagliato. @dynamic dice che gli accessor vengono risolti in fase di esecuzione, a meno che non vengano dichiarati nella classe o nella superclasse (non altrove). Puoi leggere la documentazione developer.apple.com/library/mac/documentation/cocoa/conceptual/…
user1447414

5
Kevlar: no. Nel moderno ObjC, gli @propertyoggetti che non hanno @synthesize@dynamicsaranno sintetizzati automaticamente. Per ogni proprietà, _propertyNameverrà creato un ivar con un carattere di sottolineatura iniziale, ad es. , Insieme al getter e al setter appropriati.
Dave R,

212

Dai un'occhiata a questo articolo ; sotto la voce "Metodi forniti in fase di esecuzione":

Alcuni accessori vengono creati dinamicamente in fase di runtime, come alcuni utilizzati nella classe NSManagedObject di CoreData. Se si desidera dichiarare e utilizzare le proprietà per questi casi, ma si desidera evitare avvisi sui metodi mancanti in fase di compilazione, è possibile utilizzare la direttiva @dynamic anziché @synthesize.

...

L'uso della direttiva @dynamic in sostanza dice al compilatore "non preoccuparti, è in arrivo un metodo".

La @synthesizedirettiva, d'altra parte, genera i metodi di accesso per te in fase di compilazione (sebbene, come notato nella sezione "Miscelazione di accessori sintetizzati e personalizzati", è flessibile e non genera metodi per te se entrambi sono implementati).


27
Questo è un uomo più corretto. Questa risposta è l'unica risposta che parla di metodi creati in fase di runtime, che sembra catturare lo spirito molto di più rispetto ai più votati ans
bobobobo

30

Come altri hanno già detto, in generale usi @synthesize per fare in modo che il compilatore generi i getter e / o le impostazioni per te, e @dynamic se hai intenzione di scriverli tu stesso.

C'è un'altra sottigliezza non ancora menzionata: @synthesize ti consentirà di implementare tu stesso un getter o un setter. Ciò è utile se si desidera implementare il getter solo per qualche logica aggiuntiva, ma lasciare che il compilatore generi il setter (che, per gli oggetti, di solito è un po 'più complesso da scrivere).

Tuttavia, se si scrive un'implementazione per un accessor @ synthesize, deve comunque essere supportato da un campo reale (ad esempio, se si scrive -(int) getFoo();è necessario disporre di un int foo;campo). Se il valore viene prodotto da qualcos'altro (ad es. Calcolato da altri campi), devi usare @dynamic.


2
+1 per menzionare la differenza importante: @dynamic ti consente di creare accessori per variabili non definite nell'interfaccia della tua classe e attraverso l'introspezione.
Mahboudz,

24
"e @dynamicse hai intenzione di scriverli tu stesso" No, NON usi la dinamica se li scrivi tu. @dynamicdisattiva il controllo del compilatore per assicurarsi di averli implementati. Se li hai implementati tu stesso, vuoi che il compilatore controlli.
user102008

14

@dynamic è generalmente usato (come è stato detto sopra) quando una proprietà viene creata dinamicamente in fase di esecuzione. NSManagedObject fa questo (perché tutte le sue proprietà sono dinamiche) - che elimina alcuni avvisi del compilatore.

Per una buona panoramica su come creare proprietà dinamicamente (senza NSManagedObject e CoreData :, vedere: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#// apple_ref / doc / uid / TP40008048-CH102-SW1


14

ecco un esempio di @dinamico

#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;
}

10

Secondo la documentazione:

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

@dynamic dice al compilatore che i metodi di accesso sono forniti in fase di esecuzione.

Con un po 'di indagine ho scoperto che fornire metodi di accesso ha la precedenza sulla direttiva @dynamic.

@synthesize dice al compilatore di creare quegli accessor per te (getter e setter)

@property dice al compilatore che gli accessor verranno creati e a cui è possibile accedere con la notazione punto o [messaggio oggetto]


6

Una cosa da aggiungere è che se una proprietà viene dichiarata come @dinamica non occuperà memoria (ho confermato con lo strumento di allocazione). Una conseguenza è che puoi dichiarare la proprietà nella categoria di classe.


Se eseguo l'override di un setter di proprietà in una categoria e lo rendo dinamico, ciò garantirà che l'override verrà utilizzato in fase di esecuzione e non il setter della classe genitore? Dai documenti Apple: "Se il nome di un metodo dichiarato in una categoria è uguale a un metodo nella classe originale ... il comportamento non è definito su quale implementazione del metodo viene utilizzata in fase di esecuzione."
David James,

No, penso che il comportamento sia ancora indefinito. Rendere dinamica la proprietà nella categoria non modifica la priorità di runtime del metodo del setter proprietà.
Yingpei Zeng

3

Come da documentazione Apple.

Si utilizza l' @synthesizeistruzione nel blocco di implementazione di una classe per indicare al compilatore di creare implementazioni che corrispondono alla specifica fornita nella @propertydichiarazione.

Utilizzare l' @dynamicistruzione per indicare al compilatore di sopprimere un avviso se non riesce a trovare un'implementazione dei metodi di accesso specificati da una @propertydichiarazione.

Ulteriori informazioni:-

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.