Heim  >  Artikel  >  Backend-Entwicklung  >  @dynamic in Objective-C

@dynamic in Objective-C

高洛峰
高洛峰Original
2016-12-13 09:09:241099Durchsuche

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 

#import "Book.h"

 

int main(int argc, const char * argv[])

{

 

    @autoreleasepool

    {

        Book *book = [[Book alloc] init];

       book.name = @ "c++ primer";

       book.author = @"Stanley B.Lippman";

        book.version = @"5.0";

        NSLog(@"%@ ", book.name);

        NSLog(@"%@", book.author);

        NSLog(@"%@", book.version);

&能以前, Sie haben die Methode „methodSignatureForSelector:“ und „forwardInvocation:“ verwendet的方法签名.forwardInvocation:将选择器转发给一个真正实现了该消息的对象.

 

2)Objective-C 。举两个例子来说明:

    例一:- (NSString *)name )val

这个方法实际上有三个参数:self, _cmd和val.

   型有如下的要求:

    A .第一个参数类型必须是id(就是self的类型)

    B.第二个参数类型必须是SEL(就是_cmd的类型)

    C.从第三个参数起,可以按照原方法的参数类型定义。举两个例子来说明:

    例一:setHeight:(CGFloat)height中的参数height是浮点型的,所以第三个参数类型就是f.

    例二: Sie können setName:(NSString *)name verwenden 🎜>

 

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.


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn