Heim >Java >javaLernprogramm >Einführung in die Verwendung von @dynamic
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'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'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).