@synthesize против @dynamic, в чем различия? - PullRequest
547 голосов
/ 21 июля 2009

Каковы различия между реализацией @property с @dynamic или @synthesize?

Ответы [ 8 ]

729 голосов
/ 21 июля 2009

@ synthesize сгенерирует методы получения и установки для вашего свойства. @dynamic просто сообщает компилятору, что методы getter и setter реализуются не самим классом, а где-то еще (например, суперклассом или будут предоставлены во время выполнения).

Использование @dynamic, например: с подклассами NSManagedObject (CoreData) или когда вы хотите создать выход для свойства, определенного суперклассом, который не был определен как выход.

@ dynamic также может использоваться для делегирования ответственности за реализацию средств доступа. Если вы реализуете методы доступа внутри класса, то обычно не используете @ dynamic.

Супер класс:

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

Подкласс:

@property (nonatomic, retain) IBOutlet NSButton *someButton;
...
@dynamic someButton;
211 голосов
/ 21 июля 2009

Взгляните на эту статью ; под заголовком «Методы, предоставляемые во время выполнения»:

Некоторые методы доступа создаются динамически во время выполнения, например, некоторые из них используются в классе CoreData NSManagedObject. Если вы хотите объявить и использовать свойства для этих случаев, но хотите избежать предупреждений о методах, отсутствующих во время компиляции, вы можете использовать директиву @dynamic вместо @ synthesize.

...

Использование директивы @dynamic, по сути, говорит компилятору: «Не беспокойтесь об этом, метод уже в пути».

Директива @synthesize, с другой стороны, генерирует методы доступа для вас во время компиляции (хотя, как отмечено в разделе «Смешивание синтезированных и пользовательских методов доступа», она гибкая и не генерирует для вас методы, если реализована).

29 голосов
/ 21 июля 2009

Как уже говорили другие, вы обычно используете @synthesize, чтобы компилятор генерировал для вас геттеры и / или настройки, и @dynamic, если вы собираетесь их писать самостоятельно.

Есть еще одна тонкость, еще не упомянутая: @synthesize будет позволять вам предоставлять реализацию самостоятельно, либо с использованием метода получения, либо установки. Это полезно, если вы хотите реализовать метод получения только для некоторой дополнительной логики, но позволить компилятору сгенерировать метод установки (который для объектов обычно немного сложнее написать самостоятельно).

Однако, если вы пишете реализацию для метода доступа @ synthesize, он все равно должен быть поддержан реальным полем (например, если вы пишете -(int) getFoo();, у вас должно быть поле int foo;). Если значение создается чем-то другим (например, вычисляется из других полей), тогда вы должны использовать @ dynamic.

14 голосов
/ 11 сентября 2013

здесь пример @ 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;
}
14 голосов
/ 26 ноября 2011

@ dynamic обычно используется (как уже было сказано выше), когда свойство динамически создается во время выполнения. NSManagedObject делает это (почему все его свойства являются динамическими), что подавляет некоторые предупреждения компилятора.

Хороший обзор того, как динамически создавать свойства (без NSManagedObject и CoreData: см. http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#//apple_ref/doc/uid/TP40008048-CH102-SW1

10 голосов
/ 03 декабря 2013

Согласно документации:

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

@ dynamic сообщает компилятору, что методы доступа предоставляются во время выполнения.

После небольшого исследования я обнаружил, что предоставление методов доступа переопределяет директиву @dynamic.

@ synthesize указывает компилятору создать для вас эти методы доступа (геттер и сеттер)

свойство @ сообщает компилятору, что средства доступа будут созданы, и к ним можно обратиться с помощью точечной нотации или [объекта сообщения]

6 голосов
/ 13 мая 2013

Хочется добавить, что если свойство объявлено как @dynamic, оно не будет занимать память (я подтвердил это с помощью инструмента выделения). Как следствие, вы можете объявить свойство в категории класса.

1 голос
/ 16 декабря 2015

Согласно документации Apple.

Вы используете оператор @synthesize в блоке реализации класса, чтобы сказать компилятору создавать реализации, которые соответствуют спецификации, которую вы дали в объявлении @property.

Вы используете оператор @dynamic, чтобы сказать компилятору подавить предупреждение, если он не может найти реализацию методов доступа, указанных в объявлении @property.

Дополнительная информация: -

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

...