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

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

<p>@synthesize сгенерирует методы getter и setter для вашей собственности. @dynamic просто сообщает компилятору, что методы getter и setter реализуются не самим классом, а где-то еще (например, суперклассом или будут предоставлены во время выполнения).</p><p>использование для @dynamic, например, с подклассами <code>nsmanagedobject</code> (coredata) или когда вы хотите создать выход для свойства, определенного суперклассом, который не был определен как выход.</p><p>@dynamic также может использоваться для делегирования ответственности за реализацию методов доступа. если вы сами реализуете методы доступа внутри класса, то вы обычно не используете @dynamic.</p><p>супер класс:</p><pre><code>@property (nonatomic, retain) nsbutton *somebutton; ... @synthesize somebutton; </code></pre><p>подкласс:</p><pre><code>@property (nonatomic, retain) iboutlet nsbutton *somebutton; ... @dynamic somebutton; </code></pre>

<p>взгляните на <a href="http://theocacao.com/document.page/516">эта статья</a> ; под заголовком "методы, предоставляемые во время выполнения":</p><blockquote> <p>некоторые методы доступа создаются динамически во время выполнения, например, некоторые из них используются в классе coredata nsmanagedobject. если вы хотите объявить и использовать свойства для этих случаев, но хотите избежать предупреждений о методах, отсутствующих во время компиляции, вы можете использовать директиву @dynamic вместо @synthesize.</p> <p>...</p> <p>использование директивы @dynamic, по сути, говорит компилятору: "не беспокойтесь об этом, метод уже в пути".</p> </blockquote><p>директива <code>@synthesize</code>, с другой стороны, генерирует методы доступа для вас во время компиляции (хотя, как отмечено в разделе "смешивание синтезированных и пользовательских методов доступа", она гибкая и не генерирует методы для вас, если они реализованы).</p>

<p>как уже говорили другие, вы обычно используете @synthesize, чтобы компилятор генерировал для вас геттеры и/или настройки, и @dynamic, если вы собираетесь писать их самостоятельно.</p><p>есть еще одна тонкость, которая еще не упомянута: @synthesize <em>will</em> позволяет вам предоставить реализацию самостоятельно, либо с использованием метода получения, либо с установщиком. это полезно, если вы хотите реализовать метод получения только для некоторой дополнительной логики, но позволить компилятору сгенерировать метод установки (который для объектов обычно немного сложнее написать самостоятельно).</p><p>однако, если вы пишете реализацию для метода доступа @ synthesize, он все равно должен поддерживаться реальным полем (например, если вы пишете <code>-(int) getfoo();</code>, у вас должно быть поле <code>int foo;</code>). если значение создается чем-то другим (например, вычисляется из других полей), тогда вы должны использовать @dynamic.</p>

<p> <a href="https://gist.github.com/mdippery/651966">здесь</a> пример @dynamic</p><pre><code>#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; } </code></pre>

<p>@dynamic обычно используется (как уже было сказано выше), когда свойство динамически создается во время выполнения. nsmanagedobject делает это (почему все его свойства являются динамическими), что подавляет некоторые предупреждения компилятора.</p><p>хороший обзор того, как динамически создавать свойства (без nsmanagedobject и coredata :, см .: <a href="http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objcruntimeguide/articles/ocrtdynamicresolution.html#//apple\_ref/doc/uid/tp40008048-ch102-sw1">http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objcruntimeguide/articles/ocrtdynamicresolution. html # // apple\_ref/doc/uid/tp40008048-ch102-sw1</a> </p>

<p>согласно документации:</p><p> <a href="https://developer.apple.com/library/mac/documentation/cocoa/conceptual/objcruntimeguide/articles/ocrtdynamicresolution.html">https://developer.apple.com/library/mac/documentation/cocoa/conceptual/objcruntimeguide/articles/ocrtdynamicresolution.html</a> </p><p>@dynamic сообщает компилятору, что методы доступа предоставляются во время выполнения.</p><p>после небольшого исследования я обнаружил, что предоставление методов доступа переопределяет директиву @dynamic.</p><p>@synthesize говорит компилятору создать эти методы доступа для вас (getter и setter)</p><p>@property сообщает компилятору, что методы доступа будут созданы, и к ним можно получить доступ с помощью точечной нотации или [объекта сообщения]</p>

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

<p><strong> <em> согласно документации apple. </em> </strong></p><p>вы используете оператор <code>@synthesize</code> в блоке реализации класса, чтобы сообщить компилятору о создании реализаций, соответствующих спецификации, указанной вами в объявлении <code>@property</code>.</p><p>вы используете оператор <code>@dynamic</code>, чтобы сказать компилятору подавить предупреждение, если он не может найти реализацию методов доступа, указанных в объявлении <code>@property</code>.</p><p><strong> <em> дополнительная информация: - </em> </strong></p><p> <a href="https://developer.apple.com/library/ios/documentation/general/conceptual/devpedia-cocoacore/declaredproperty.html">https://developer.apple.com/library/ios/documentation/general/conceptual/devpedia-cocoacore/declaredproperty.html</a> </p>