1. Der Unterschied zwischen @dynamic und @synthesize
@property hat zwei entsprechende Wörter, eines ist @synthesize und das andere ist @dynamic. Wenn weder @synthesize noch @dynamic geschrieben sind, lautet der Standardwert @syntheszie var = _var;
Die Semantik von @synthesize besteht darin, dass Sie die Setter- und Getter-Methode nicht manuell implementieren Dann kompilieren. Der Compiler fügt diese beiden Methoden automatisch für Sie hinzu.
@dynamic teilt dem Compiler mit, dass die Setter- und Getter-Methoden der Eigenschaften vom Benutzer selbst implementiert und nicht automatisch generiert werden. (Für schreibgeschützte Eigenschaften müssen Sie natürlich nur einen Getter bereitstellen.) Wenn eine Eigenschaft als @dynamic var deklariert ist und Sie keine @setter-Methoden und @getter-Methoden bereitstellen, tritt beim Kompilieren kein Problem auf. Wenn das Programm jedoch mit „instance.var = someVar“ ausgeführt wird, stürzt das Programm ab Fehlende Setter-Methoden; oder wenn someVar = var ausgeführt wird, führt das Fehlen einer Getter-Methode ebenfalls zu einem Absturz. Zur Kompilierungszeit gibt es kein Problem und die entsprechende Methode wird erst zur Laufzeit ausgeführt. Dies ist die sogenannte dynamische Bindung.
2. Implementieren Sie @dynamic-Zugriffsmethoden über private Variablen
1) Book.h
#import
#import
@interface Book :NSObject
{
@private
__strong NSString *_name;
__strong NSString *_author;
}
@property(nonatomic, copy) NSString * name;
@property(nonatomic, copy) NSString *author;
@property(nonatomic, copy) NSString*version;
@end
2) Book.m
#import "Book.h"
@implementation Book
@dynamic name;
@dynamicauthor;
@synthesizeversion = _version;
- (id)init
{
self = [super init];
if(self)
{
}
return self ;
}
- (NSString *)name
{
if(nil == _name)
{
_name = @"Sie haben den Namen des Eingabebuchs vergessen";
}
return _name;
}
- (void)setName:(NSString *)name
{
_name = name;
NSLog(@"_name address:%p", _name );
}
- (NSString *)author
{
if(nil == _author)
{
_author = @"Sie haben den Autor des Eingabebuchs vergessen";
}
return _author;
}
- (void)setAuthor:(NSString *)author
{
_author = author;
}
@ Ende
Wie Sie dem obigen Code entnehmen können, können Sie nach der Verwendung von @dynamic auf eine private Variable in der Zugriffsmethode zugreifen, um einen Wert zuzuweisen oder abzurufen. Und @synthesize verwendet direkt @synthesize var = _var;, um Attribute und private Variablen direkt gleichzusetzen. Dies ist der Unterschied in der Schreibform zwischen den beiden.
3. Implementieren Sie die @dynamic-Zugriffsmethode durch Nachrichtenweiterleitung
Wenn @dynamic var = _var für ein Attribut verwendet wird, meldet der Compiler sofort einen Fehler. Auf diese Weise können Sie _var nicht in der Setter-Methode und Getter-Methode von var wie @synthesize verwenden. Natürlich können Sie die folgende Setter-Methode und Getter-Methode nicht schreiben:
- (void)setVar:(id)newVar
{
self.var =newVar;
}
- (void)var
{
return self.var;
}
Diese beiden Methoden rufen sich selbst auf, was zu einer Endlosschleife und direkt zum Absturz des Programms führt.
Hier ist eine Möglichkeit, @dynamic-Setter- und Getter-Methoden mithilfe des Nachrichtenweiterleitungsmechanismus zu implementieren.
Erster Code:
1) Book.h
#import
@ Schnittstelle Buch :NSObject
{
@private
NSMutableDictionary *_propertiesDict;
}
@property ( nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString*author;
@property (nonatomic, copy) NSString*version;
@end
2) Book.m
#import "Book.h"
@implementation Book
@dynamic name; // Kann nicht als name = _name geschrieben werden; sonst meldet der Compiler sofort einen Fehler
@dynamic author;
@synthesizeversion;
- (id)init
{
self = [super init];
if(self)
{ 🎜>
- (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:&objatIndex:2]; [_propertiesDict setObject:obj forKey:key]; } else { NSString *obj = [_propertiesDict objectForKey:key]; [invocation-setReturnValue:&obj]; }} @end 3)main.m#import
3)在main.m中有一句代码是book.name = @"c++ primer";里并没有这个方法Sie können die Methode „methodSignatureForSelector“ verwenden
Was ist hier v@:@? Tatsächlich stellt das erste Zeichen v hier dar, dass der Rückgabetyp der Funktion ungültig ist. Die nächsten drei Zeichen können anhand der Erklärung in 2) oben ermittelt werden. Es handelt sich um die Typen der drei Parameter self, _cmd, name,. id, SEL, NSString.
Anschließend ruft das Programm die Methode „forwardInvocation“ auf. Der erhaltene Schlüssel ist der Methodenname setName:. Verwenden Sie dann [invocationgetArgument:&objatIndex:2], um den Parameterwert abzurufen. Hier ist „C++-Primer“. Warum muss der Index hier 2 sein? Wie zuvor analysiert, ist der 0. Parameter self, der 1. Parameter ist _cmd und der 2. Parameter ist der Parameter hinter der Methode.
Abschließend verwenden Sie ein Variablenwörterbuch, um Werte zuzuweisen. Damit ist der gesamte Setter-Prozess abgeschlossen.
4) Es gibt einen Code in main.m, der NSLog(@"%@", book.name); lautet. Wenn das Programm hier ausgeführt wird, wechselt es zu Book. m, um es zu finden. Allerdings gibt es in Book.m keine solche Wertmethode, daher gibt das Programm methodSignatureForSelector: ein, um die Nachricht weiterzuleiten. Nach der Ausführung wird „@@:“ als Methodensignaturtyp zurückgegeben. Hier repräsentiert das erste Zeichen @ den Funktionsrückgabetyp NSString, das zweite Zeichen @ repräsentiert die Typ-ID von self und das dritte Zeichen: repräsentiert den Typ SEL von _cmd.
Anschließend ruft das Programm die Methode „forwardInvocation“ auf. Der erhaltene Schlüssel ist der Methodenname name. Schließlich wird der entsprechende Wert anhand dieses Schlüssels aus dem Wörterbuch abgerufen, wodurch der gesamte Getter-Prozess abgeschlossen ist.
5) Beachten Sie, dass wir beim Debuggen des Codes festgestellt haben, dass nur die Zuweisung und der Wert von Name und Autor in methodSignatureForSelector: und forwardInvocation: eingegeben werden. Es gibt auch eine Attributversion, die die beiden Methoden methodSignatureForSelector: und forwardInvocation: nicht enthält. Dies liegt daran, dass das Versionsattribut als @synthesize markiert ist und der Compiler automatisch die Methoden setVersion und version hinzufügt, sodass die Nachricht nicht weitergeleitet werden muss.
4. Die Verwendung von @dynamic in Unterklassen von NSManagedObject
Die häufigste Verwendung von @dynamic erfolgt derzeit in NSManagedObject Programmier-Setter- und Getter-Methode. Der Grund dafür ist: @dynamic weist den Compiler an, keine Verarbeitung durchzuführen, sodass die Getter- und Setter-Methoden zur Laufzeit dynamisch erstellt werden und das Core Data-Framework Zugriffsmethoden für solche Eigenschaften generiert.