@synthesize vs @dynamic, quais são as diferenças?

Respostas:

744

O @synthesize gerará métodos getter e setter para sua propriedade. O @dynamic diz ao compilador que os métodos getter e setter são implementados não pela própria classe, mas em algum outro lugar (como a superclasse ou será fornecida em tempo de execução).

Os usos para @dynamic são, por exemplo, com subclasses de NSManagedObject(CoreData) ou quando você deseja criar uma saída para uma propriedade definida por uma superclasse que não foi definida como uma saída.

O @dynamic também pode ser usado para delegar a responsabilidade de implementar os acessadores. Se você implementa os acessadores dentro da classe, normalmente não usa @dynamic.

Super classe:

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

Subclasse:

@property (nonatomic, retain) IBOutlet NSButton *someButton;
...
@dynamic someButton;
morrerikh
fonte
25
não 100% certo; dinâmico é o padrão se você não definir @synthesize ou @dynamic. especificar @dynamic significa apenas que você assume a responsabilidade de implementar adequadamente os acessadores de propriedade com base na assinatura da declaração de propriedade.
Kevlar
68
Na verdade, @dynamic significa que a responsabilidade de implementar os acessadores é delegada. Se você implementa os acessadores dentro da classe, normalmente não usa @dynamic.
22224 morrerikh
2
Eu estava recebendo NSUnknownKeyExceptionerros com minha propriedade dinâmica quando removi a @synthesizelinha (o Xcode 3.2 estava me dando um erro porque eu não tinha ivar correspondente para minha @ propriedade). A adição @dynamiccorrigiu o problema - compila e roda bem agora. Obrigado!
pix0r 14/09/09
4
Desculpe, compre isso totalmente errado. O @dynamic informa que os acessadores são resolvidos em tempo de execução, a menos que sejam declarados na classe ou na superclasse (não em outro lugar). Você pode ler a documentação developer.apple.com/library/mac/documentation/cocoa/conceptual/…
user1447414
5
Kevlar: não. Na ObjC moderna, @propertyitens que não possuem @synthesizenem @dynamicserão sintetizados automaticamente. Para cada propriedade, um ivar com um sublinhado à esquerda, por exemplo, _propertyNameserá criado, juntamente com o getter e o setter apropriados.
Dave R
212

Dê uma olhada neste artigo ; sob o título "Métodos fornecidos em tempo de execução":

Alguns acessadores são criados dinamicamente em tempo de execução, como alguns usados ​​na classe NSManagedObject do CoreData. Se você deseja declarar e usar propriedades para esses casos, mas deseja evitar avisos sobre métodos ausentes no momento da compilação, use a diretiva @dynamic em vez de @synthesize.

...

O uso da diretiva @dynamic diz essencialmente ao compilador "não se preocupe, um método está a caminho".

A @synthesizediretiva, por outro lado, gera os métodos de acessador para você em tempo de compilação (embora, conforme observado na seção "Misturando acessores sintetizados e personalizados", seja flexível e não gere métodos para você, se algum deles estiver implementado).

Alex Rozanski
fonte
27
Este é um homem mais correto. Esta resposta é a única resposta que fala sobre métodos criados em tempo de execução, o que realmente parece captar o espírito muito mais do que mais votados ans atm
bobobobo
30

Como outros já disseram, em geral você usa @synthesize para que o compilador gere os getters e / ou configurações para você e @dynamic se você mesmo os escrever.

Há outra sutileza ainda não mencionada: @synthesize permitirá que você forneça uma implementação, seja de um getter ou de um setter. Isso é útil se você deseja implementar o getter apenas para uma lógica extra, mas permite que o compilador gere o setter (que, para objetos, geralmente é um pouco mais complexo de se escrever).

No entanto, se você escrever uma implementação para um acessador @ synthesize'd, ainda deverá ser apoiada por um campo real (por exemplo, se você escrever, -(int) getFoo();deverá ter um int foo;campo). Se o valor estiver sendo produzido por outra coisa (por exemplo, calculado a partir de outros campos), você deverá usar @dynamic.

philsquared
fonte
2
+1 por menção de diferença importante: @dynamic permite criar acessadores para variáveis ​​não definidas na interface da sua classe e através da introspecção.
mahboudz 20/11/2009
24
"e @dynamicse você mesmo escrever" Não, você NÃO usa dinâmico se você mesmo os escrever. @dynamicdesativa a verificação do compilador para garantir que você os implementou. Se você os implementou, deseja que o compilador verifique.
user102008
14

@dynamic é normalmente usado (como foi dito acima) quando uma propriedade está sendo criada dinamicamente em tempo de execução. O NSManagedObject faz isso (por que todas as suas propriedades são dinâmicas) - que suprimem alguns avisos do compilador.

Para obter uma boa visão geral de como criar propriedades dinamicamente (sem NSManagedObject e CoreData :, consulte: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#// apple_ref / doc / uid / TP40008048-CH102-SW1

mifortin
fonte
14

aqui está um exemplo 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;
}
espelho
fonte
10

Conforme a documentação:

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

@dynamic informa ao compilador que os métodos acessadores são fornecidos em tempo de execução.

Com um pouco de investigação, descobri que o fornecimento de métodos de acessor substitui a diretiva @dynamic.

O @synthesize diz ao compilador para criar esses acessadores para você (getter e setter)

@property informa ao compilador que os acessadores serão criados e que podem ser acessados ​​com a notação de ponto ou [mensagem de objeto]

user1447414
fonte
6

Uma coisa a acrescentar é que, se uma propriedade for declarada como @dynamic, ela não ocupará memória (confirmei com o instrumento de alocação). Uma conseqüência é que você pode declarar propriedade na categoria de classe.

Yingpei Zeng
fonte
Se eu substituir um configurador de propriedades em uma categoria e torná-lo dinâmico, isso garantirá que a substituição será usada no tempo de execução e não o configurador da classe pai? Da documentação da Apple: "Se o nome de um método declarado em uma categoria for o mesmo que um método da classe original ... o comportamento será indefinido sobre qual implementação de método é usada em tempo de execução".
David James
Não, acho que o comportamento ainda é indefinido. Tornar a propriedade na categoria dinâmica não altera a prioridade de tempo de execução do método do configurador de propriedades.
Yingpei Zeng 07/04
3

Conforme a documentação da Apple.

Você usa a @synthesizeinstrução no bloco de implementação de uma classe para informar ao compilador para criar implementações que correspondem à especificação que você forneceu na @propertydeclaração.

Você usa a @dynamicinstrução para instruir o compilador a suprimir um aviso se ele não conseguir encontrar uma implementação dos métodos de acessador especificados por uma @propertydeclaração.

Mais informações:-

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

arango_86
fonte