@synthesize vs @dynamic, які відмінності?


Відповіді:


744

@synthesize створить для вашої власності методи отримання та налаштування. @dynamic просто повідомляє компілятору, що методи getter та setter реалізуються не самим класом, а десь іншим (наприклад, суперклас або буде надано під час виконання).

Використання для @dynamic є, наприклад, з підкласами NSManagedObject(CoreData) або коли ви хочете створити розетку для властивості, визначеної суперкласом, який не був визначений як розетка.

@dynamic також може використовуватися для делегування відповідальності за реалізацію доступу. Якщо ви реалізуєте аксесуари самостійно в класі, то зазвичай ви не використовуєте @dynamic.

Супер клас:

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

Підклас:

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

25
не на 100% правильно; за замовчуванням є динамічним, якщо ви не встановите ні @synthesize, ні @dynamic. Вказівка ​​@dynamic означає лише, що ви берете на себе відповідальність за належну імплементацію доступу майнових даних на основі підпису декларації про властивість.
Кевлар

68
Насправді, @dynamic означає відповідальність за реалізацію доступу. Якщо ви реалізуєте аксесуари самостійно в класі, то зазвичай ви не використовуєте @dynamic.
dieerikh

2
Я отримував NSUnknownKeyExceptionпомилки зі своїм динамічним властивістю, коли я видаляв @synthesizeрядок (Xcode 3.2 давав мені помилку b / c. У мене не було відповідного ivar для мого @property). Додавання @dynamicвиправленої проблеми - збирається та працює нормально. Дякую!
pix0r

4
Вибачте, купувати це абсолютно неправильно. @dynamic повідомляє, що аксесуари вирішуються під час виконання, якщо тільки вони не оголошені в класі або суперкласі (не деінде). Ви можете прочитати документацію developer.apple.com/library/mac/documentation/cocoa/conceptual/…
user1447414

5
Кевлар: ні. У сучасному ObjC @propertyелементи, які не мають ні, @synthesizeні @dynamicбудуть автоматично синтезовані. Для кожної властивості буде створено ivar з провідним підкресленням, наприклад _propertyName, разом із відповідним геттером та сеттером.
Дейв R

212

Погляньте на цю статтю ; під заголовком "Методи, що надаються під час виконання":

Деякі аксесуари створюються динамічно під час виконання, наприклад, такі, які використовуються в класі NSManagedObject CoreData. Якщо ви хочете оголосити та використовувати властивості для цих випадків, але хочете уникати попереджень про відсутність методів під час компіляції, можете використовувати директиву @dynamic замість @synthesize.

...

Використання директиви @dynamic по суті каже компілятору "не хвилюйтеся з цього приводу, метод на шляху".

@synthesizeДиректива, з іншого боку, створює методи доступу для вас під час компіляції (хоча , як відзначався в розділі «Змішування синтезатор і призначене для користувача Accessors» він є гнучким і не створює методи для вас , якщо або реалізується).


27
Це morer-коректор людини. Ця відповідь є єдиною відповіддю, яка розповідає про методи, створені під час виконання, які, здається, захоплюють дух набагато більше, ніж найкращі голосовані відповіді
atmm

30

Як вже говорили інші, ти, як правило, використовуєш @synthesize, щоб компілятор генерував для тебе геть та / або налаштування, і @dynamic, якщо ти збираєшся їх самостійно писати.

Існує ще одна тонкість ще не згадав: @synthesize буде перешкоджати вам забезпечити реалізацію себе, або геттер або сетера. Це корисно, якщо ви хочете реалізувати геттер лише за деякою додатковою логікою, але дозвольте компілятору генерувати сеттер (що для об'єктів, як правило, трохи складніше написати самому).

Однак якщо ви пишете реалізацію для аксесуара @ synthesize'd, вона все одно повинна бути підкріплена реальним полем (наприклад, якщо ви пишете, у -(int) getFoo();вас повинно бути int foo;поле). Якщо значення виробляється чимось іншим (наприклад, обчислюється з інших полів), тоді вам доведеться використовувати @dynamic.


2
+1 для згадування важливої ​​різниці: @dynamic дозволяє створювати аксесуари для змінних, які не визначені в інтерфейсі вашого класу, і за допомогою самоаналізу.
mahboudz

24
@dynamicякщо ви збираєтеся їх самостійно писати" Ні, ви НЕ використовуєте динаміку, якщо ви пишете їх самі. @dynamicвимикає перевірку компілятора, щоб переконатися, що ви їх реалізували. Якщо ви їх реалізували самостійно, ви хочете перевірити компілятор.
користувач102008

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


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 повідомляє компілятору створити для вас ці аксесуари (геттер і сетер)

@property повідомляє компілятору, що будуть створені аксесуари, і що їх можна отримати за допомогою позначення крапки або [об'єктного повідомлення]


6

Хочемо додати, що якщо властивість оголошено як @dynamic, воно не буде займати пам'ять (я підтвердив інструмент розподілу). Наслідком цього є те, що ви можете оголосити властивість у категорії класів.


Якщо я замінюю налаштування властивостей у категорії і роблю її динамічною, чи гарантує це переопрацювання під час виконання, а не сетер батьківського класу? З документів Apple: "Якщо назва методу, оголошеного в категорії, збігається з методом у початковому класі ... поведінка не визначена щодо того, який спосіб використання використовується під час виконання".
Девід Джеймс

Ні, я думаю, що поведінка все ще не визначена. Перетворення властивості в категорії динамічним не змінює пріоритет методу встановлення властивості.
Yingpei Zeng

3

Відповідно до документації Apple.

Ви використовуєте @synthesizeоператор у блоці реалізації класу, щоб повідомити компілятору створити реалізації, які відповідають специфікації, яку ви дали у@property декларації.

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

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.