@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 @synthesizené @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.