@synthesize против @dynamic, в чем различия?

Ответы:

744

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

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

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

Супер класс:

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

Подкласс:

@property (nonatomic, retain) IBOutlet NSButton *someButton;
...
@dynamic someButton;
diederikh
источник
25
не на 100% верно; По умолчанию используется динамический, если вы не установили ни @synthesize, ни @dynamic. указание @dynamic просто означает, что вы берете на себя ответственность за правильную реализацию средств доступа к свойствам на основе подписи объявления свойства.
Кевлар
68
Не совсем, @dynamic означает, что ответственность за реализацию методов доступа делегирована. Если вы сами реализуете методы доступа внутри класса, то вы обычно не используете @dynamic.
Дидерих
2
Я получал NSUnknownKeyExceptionошибки с моим динамическим свойством, когда я удалял @synthesizeстроку (Xcode 3.2 выдавал мне ошибку, потому что у меня не было соответствующего ivar для моего @property). Добавление @dynamicисправило проблему - теперь компилируется и работает нормально. Спасибо!
pix0r
4
Извините, купить это совершенно неправильно. @dynamic сообщает, что средства доступа разрешаются во время выполнения, если они не объявлены в классе или суперклассе (не где-то еще). Вы можете прочитать документацию developer.apple.com/library/mac/documentation/cocoa/conceptual/...
user1447414
5
Кевлар: Нет. В современном ObjC @propertyпредметы, которые не имеют и @synthesizeне @dynamicбудут автоматически синтезироваться. Для каждого свойства будет создан ивар с начальным подчеркиванием, например _propertyName, вместе с соответствующим геттером и сеттером.
Дэйв Р
212

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

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

...

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

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

Алекс Розанский
источник
27
Это человек-корректор. Этот ответ является единственным ответом, в котором говорится о методах, созданных во время выполнения, которые действительно, кажется, захватывают дух намного больше, чем голосующие топ-
лидеры
30

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

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

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

philsquared
источник
2
+1 за упоминание важного различия: @dynamic позволяет создавать средства доступа для переменных, не определенных в интерфейсе вашего класса и посредством самоанализа.
Махбудз
24
@dynamicесли вы собираетесь написать их самостоятельно" Нет, вы НЕ используете динамические, если вы пишете их сами. @dynamicотключает проверку компилятора, чтобы убедиться, что вы реализовали их. Если вы реализовали их сами, вы хотите, чтобы компилятор проверил.
user102008
14

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

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

mifortin
источник
14

вот пример @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;
}
зеркало
источник
10

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

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

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

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

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

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

user1447414
источник
6

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

Инпэй Цзэн
источник
Если я переопределю установщик свойства в категории и сделаю его динамическим, будет ли это гарантировать, что переопределение будет использоваться во время выполнения, а не установщика родительского класса? Из документов Apple: «Если имя метода, объявленного в категории, совпадает с именем метода в исходном классе ... поведение не определено относительно того, какая реализация метода используется во время выполнения».
Дэвид Джеймс
Нет, я думаю, что поведение все еще не определено. Создание свойства в динамической категории не меняет приоритет времени выполнения метода установки свойств.
Yingpei Zeng
3

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

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

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

Больше информации:-

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

arango_86
источник