@synthesize vs @dynamic, was sind die Unterschiede?

Antworten:

744

@synthesize generiert Getter- und Setter-Methoden für Ihre Immobilie. @dynamic teilt dem Compiler lediglich mit, dass die Getter- und Setter-Methoden nicht von der Klasse selbst implementiert werden, sondern an einer anderen Stelle (wie der Oberklasse oder zur Laufzeit bereitgestellt).

Verwendungen für @dynamic sind z. B. mit Unterklassen von NSManagedObject(CoreData) oder wenn Sie einen Ausgang für eine Eigenschaft erstellen möchten, die von einer Oberklasse definiert wurde, die nicht als Ausgang definiert wurde.

@dynamic kann auch verwendet werden, um die Verantwortung für die Implementierung der Accessoren zu delegieren. Wenn Sie die Accessoren selbst in der Klasse implementieren, verwenden Sie normalerweise nicht @dynamic.

Super Klasse:

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

Unterklasse:

@property (nonatomic, retain) IBOutlet NSButton *someButton;
...
@dynamic someButton;
diederikh
quelle
25
nicht 100% richtig; Dynamisch ist die Standardeinstellung, wenn Sie weder @synthesize noch @dynamic festlegen. Wenn Sie @dynamic angeben, übernehmen Sie lediglich die Verantwortung für die ordnungsgemäße Implementierung der Eigenschaftszugriffsberechtigten auf der Grundlage der Signatur der Eigenschaftsdeklaration.
Kevlar
68
Nicht wirklich, @dynamic bedeutet, dass die Verantwortung für die Implementierung der Accessoren delegiert wird. Wenn Sie die Accessoren selbst in der Klasse implementieren, verwenden Sie normalerweise nicht @dynamic.
Diederikh
2
Ich habe NSUnknownKeyExceptionFehler mit meiner dynamischen Eigenschaft erhalten, als ich die @synthesizeZeile entfernt habe (Xcode 3.2 hat mir einen Fehler gemeldet, da ich kein passendes ivar für meine @ Eigenschaft hatte). Das Hinzufügen @dynamicdes Problems wurde behoben - kompiliert und läuft jetzt einwandfrei. Vielen Dank!
pix0r
4
Sorry, kauf das ist völlig falsch. @dynamic gibt an, dass die Accessoren zur Laufzeit aufgelöst werden, sofern sie nicht in der Klasse oder Oberklasse deklariert sind (nicht an einer anderen Stelle). Sie können die Dokumentation developer.apple.com/library/mac/documentation/cocoa/conceptual/…
user1447414
5
Kevlar: Nein. Im modernen ObjC werden @propertyElemente, die weder automatisch synthetisiert wurden, @synthesizenoch @dynamicautomatisch synthetisiert. Für jede Eigenschaft wird ein Ivar mit einem führenden Unterstrich erstellt, z. B. _propertyNamezusammen mit dem entsprechenden Getter und Setter.
Dave R
212

Schauen Sie sich diesen Artikel an . unter der Überschrift "Zur Laufzeit bereitgestellte Methoden":

Einige Accessoren werden zur Laufzeit dynamisch erstellt, z. B. bestimmte, die in der NSManagedObject-Klasse von CoreData verwendet werden. Wenn Sie Eigenschaften für diese Fälle deklarieren und verwenden möchten, aber Warnungen vor Methoden vermeiden möchten, die zur Kompilierungszeit fehlen, können Sie die Direktive @dynamic anstelle von @synthesize verwenden.

...

Die Verwendung der @ dynamic-Direktive sagt dem Compiler im Wesentlichen: "Mach dir keine Sorgen, eine Methode ist unterwegs."

Die @synthesizeDirektive hingegen generiert die Zugriffsmethoden zur Kompilierungszeit für Sie (obwohl sie, wie im Abschnitt "Mischen von synthetisierten und benutzerdefinierten Zugriffsmethoden" angegeben, flexibel ist und keine Methoden für Sie generiert, wenn beide implementiert sind).

Alex Rozanski
quelle
27
Das ist ein mürrischer Mann. Diese Antwort ist die einzige Antwort, die über zur Laufzeit erstellte Methoden spricht, die den Geist wirklich viel mehr zu erfassen scheinen als die am besten
bewerteten und
30

Wie andere bereits gesagt haben, verwenden Sie im Allgemeinen @synthesize, damit der Compiler die Getter und / oder Einstellungen für Sie generiert, und @dynamic, wenn Sie sie selbst schreiben möchten.

Es gibt noch eine weitere Subtilität, die noch nicht erwähnt wurde: Mit @synthesize können Sie selbst eine Implementierung eines Getters oder eines Setters bereitstellen. Dies ist nützlich, wenn Sie den Getter nur für eine zusätzliche Logik implementieren möchten, den Compiler jedoch den Setter generieren lassen möchten (was für Objekte normalerweise etwas komplexer ist, sich selbst zu schreiben).

Wenn Sie jedoch eine Implementierung für einen @ synthetize'd-Accessor schreiben, muss diese weiterhin von einem realen Feld unterstützt werden (z. B. wenn Sie schreiben -(int) getFoo();, müssen Sie ein int foo;Feld haben). Wenn der Wert von etwas anderem erzeugt wird (z. B. aus anderen Feldern berechnet), müssen Sie @dynamic verwenden.

philsquared
quelle
2
+1 für die Erwähnung eines wichtigen Unterschieds: Mit @dynamic können Sie Accessoren für Variablen erstellen, die nicht in Ihrer Klassenschnittstelle definiert sind, und durch Selbstbeobachtung.
Mahboudz
24
"und @dynamicwenn Sie sie selbst schreiben wollen" Nein, Sie verwenden KEINE Dynamik, wenn Sie sie selbst schreiben. @dynamicDeaktiviert die Compilerprüfung, um sicherzustellen, dass Sie sie implementiert haben. Wenn Sie sie selbst implementiert haben, soll der Compiler dies überprüfen.
user102008
14

@dynamic wird normalerweise (wie oben erwähnt) verwendet, wenn eine Eigenschaft zur Laufzeit dynamisch erstellt wird. NSManagedObject führt dies aus (warum alle seine Eigenschaften dynamisch sind) - wodurch einige Compiler-Warnungen unterdrückt werden.

Eine gute Übersicht zum dynamischen Erstellen von Eigenschaften (ohne NSManagedObject und CoreData:) finden Sie unter: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#// apple_ref / doc / uid / TP40008048-CH102-SW1

Mifortin
quelle
14

Hier ist ein Beispiel für @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;
}
Spiegel
quelle
10

Gemäß Dokumentation:

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

@dynamic teilt dem Compiler mit, dass die Zugriffsmethoden zur Laufzeit bereitgestellt werden.

Mit ein wenig Nachforschungen fand ich heraus, dass die Bereitstellung von Accessor-Methoden die @ dynamic-Direktive überschreibt.

@synthesize weist den Compiler an, diese Accessoren für Sie zu erstellen (Getter und Setter).

@property teilt dem Compiler mit, dass die Accessoren erstellt werden und dass mit der Punktnotation oder [Objektnachricht] darauf zugegriffen werden kann.

user1447414
quelle
6

Eine Sache, die hinzugefügt werden soll, ist, dass eine Eigenschaft, die als @dynamic deklariert ist, keinen Speicher belegt (ich habe dies mit dem Zuweisungsinstrument bestätigt). Eine Konsequenz ist, dass Sie eine Eigenschaft in der Klassenkategorie deklarieren können.

Yingpei Zeng
quelle
Wenn ich einen Eigenschaftssetter in einer Kategorie überschreibe und dynamisch mache, garantiert dies, dass die Überschreibung zur Laufzeit verwendet wird und nicht der Setter der übergeordneten Klasse? Aus Apple-Dokumenten: "Wenn der Name einer in einer Kategorie deklarierten Methode mit einer Methode in der ursprünglichen Klasse identisch ist ... ist das Verhalten undefiniert, welche Methodenimplementierung zur Laufzeit verwendet wird."
David James
Nein, ich denke das Verhalten ist noch undefiniert. Wenn Sie die Eigenschaft in der Kategorie dynamisch gestalten, ändert sich die Laufzeitpriorität der Eigenschaftssetzermethode nicht.
Yingpei Zeng
3

Gemäß der Apple-Dokumentation.

Sie verwenden die @synthesizeAnweisung im Implementierungsblock einer Klasse, um den Compiler anzuweisen, Implementierungen zu erstellen, die der in der @propertyDeklaration angegebenen Spezifikation entsprechen .

Sie verwenden die @dynamicAnweisung, um den Compiler anzuweisen, eine Warnung zu unterdrücken, wenn er keine Implementierung von Zugriffsmethoden finden kann, die in einer @propertyDeklaration angegeben sind.

Mehr Info:-

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

arango_86
quelle