Heim  >  Artikel  >  Java  >  Einführung in die Verwendung von @dynamic

Einführung in die Verwendung von @dynamic

高洛峰
高洛峰Original
2016-12-13 09:18:512613Durchsuche

Einführung in die Verwendung von @dynamic

Objective-C 2.0 stellt Eigenschaften (@property) bereit, die es dem Compiler ermöglichen, automatisch Setter- und Getter-Methoden zu generieren. Wenn Sie nicht möchten, dass der Compiler diese Setter- und Getter-Methoden selbst generiert, verwenden Sie @dynamic. Um ein einfaches Beispiel zu geben, wie folgt:

#import <Foundation/Foundation.h>  
  
@interface Person : NSObject  
@property (copy) NSString *name;  
@end  
  
@implementation Person  
// @dynamic tells compiler don&#39;t generate setter and getter automatically  
@dynamic name;  
@end  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
      
    a.name = @"Hello"; // will crash here  
    NSLog(@"%@", a.name);  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

Beim Ausführen des Programms meldet Xcode einen Fehler „-[PersonsetName:]: unbekannter Selektor an Instanz 0x1001149d0 gesendet“. Wenn @dynamic auskommentiert ist, ist alles in Ordnung.

Aufgrund der Verwendung von @dynamic hier müssen wir die Setter- und Getter-Methoden selbst bereitstellen. Im Allgemeinen gibt es zwei Methoden: 1) Stellen Sie Setter- und Getter-Methoden selbst bereit und schreiben Sie die vom Compiler automatisch generierten Setter- und Getter-Methoden manuell neu. 2) Dynamische Methodenauflösung (DynamicMethod Resolution), Bereitstellung entsprechender Implementierungen von Setter- und Getter-C-Funktionen zur Laufzeit .

Für die erste Methode müssen die Instanzvariablen explizit in der Klasse bereitgestellt werden, da @dynamic keine Instanzvariablen für die Implementierungsdatei (.m) bereitstellen kann, wie dies bei @synthesize der Fall ist.

#import <Foundation/Foundation.h>  
  
@interface Person : NSObject  
{  
    // must provide a ivar for our setter and getter  
    NSString *_name;  
}  
@property (copy) NSString *name;  
@end  
  
@implementation Person  
// @dynamic tells compiler don&#39;t generate setter and getter automatically  
@dynamic name;  
  
// We provide setter and getter here  
- (void) setName:(NSString *)name  
{  
    if (_name != name) {  
        [_name release];  
        _name = [name copy];  
    }  
}  
  
- (NSString *) name  
{  
    return _name;  
}  
@end // Person  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
      
    a.name = @"Hello"; // Ok, use our setter  
    a.name = @"Hello, world";  
    NSLog(@"%@", a.name); // Ok, use our getter  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

Für die zweite Methode wird die von NSObject bereitgestellte Methode „resolveInstanceMethod:“ verwendet, um die C-Funktion zu bestimmen, die der Setter- und Getter-Implementierung zur Laufzeit entspricht. Instanzvariablen können nicht direkt in C-Funktionen verwendet werden. Daher müssen die Instanzvariablen auch explizit in der Person-Klasse deklariert werden und die Zugriffsebene ist @public Verstecken Sie die Instanzvariablen und fügen Sie die Deklaration in die Erweiterung (Erweiterung)

#import <Foundation/Foundation.h>  
#import <objc/objc-runtime.h> // for class_addMethod()  
  
// ------------------------------------------------------  
// A .h file  
@interface Person : NSObject  
@property (copy) NSString *name;  
- (void) hello;  
@end  
  
// ------------------------------------------------------  
// A .m file  
// Use extension to override the access level of _name ivar  
@interface Person ()  
{  
@public  
    NSString *_name;  
}  
@end  
  
@implementation Person  
// @dynamic implies compiler to look for setName: and name method in runtime  
@dynamic name;  
  
// Only resolve unrecognized methods, and only load methods dynamically once  
+ (BOOL) resolveInstanceMethod:(SEL)sel  
{  
    // Capture setName: and name method  
    if (sel == @selector(setName:)) {  
        class_addMethod([self class], sel, (IMP)setName, "v@:@");  
        return YES;  
    }  
    else if (sel == @selector(name)) {  
        class_addMethod([self class], sel, (IMP)getName, "@@:");  
        return YES;  
    }  
      
    return [super resolveInstanceMethod:sel];  
}  
  
void setName(id self, SEL _cmd, NSString* name)  
{  
    // Implement @property (copy)  
    if (((Person *)self)->_name != name) {  
        [((Person *)self)->_name release];  
        ((Person *)self)->_name = [name copy];  
    }  
}  
  
NSString* getName(id self, SEL _cmd)  
{  
    return ((Person *)self)->_name;  
}  
  
- (void) hello  
{  
    NSLog(@"Hello, world");  
}  
  
@end // Person  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
    [a hello]; // never call resolveInstanceMethod  
      
    a.name = @"hello1";  
    NSLog(@"%@", a.name);  
    a.name = @"hello2";  
    NSLog(@"%@", a.name);  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

ein. Zusammenfassend lässt sich sagen, dass die Funktion von @dynamic darin besteht, dem Compiler das Generieren von Setter- und Getter-Methoden für @property zu verbieten Es gibt zwei Möglichkeiten, Setter- und Getter-Methoden zu implementieren: 1) Stellen Sie Setter und Getter-Methoden selbst bereit. 2) Dynamische Methodenauflösung (DynamicMethod Resolution).

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