您好,欢迎访问一九零五行业门户网

介绍@dynamic的用法

介绍@dynamic的用法 
    objective-c 2.0提供了属性(@property),可以让编译器自动生成setter和getter方法。如果不想编译器自作主张生成这些setter和getter方法,则使用@dynamic。举个简单例子,如下
#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
运行该程序,xcode会报错“-[personsetname:]: unrecognized selector sent to instance 0x1001149d0”。如果将@dynamic注释掉,则一切ok。
这里由于使用@dynamic,我们需要自己提供setter和getter方法。一般有两种方法:1)自己提供setter和getter方法,将编译器自动生成的setter和getter方法手动再写一遍;2)动态方法决议(dynamicmethod resolution),在运行时提供setter和getter对应实现的c函数。
对于第一种方法,需要在类中显式提供实例变量,因为@dynamic不能像@synthesize那样向实现文件(.m)提供实例变量。
#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
对于第二种方法,在运行时决定setter和getter对应实现的c函数,使用了nsobject提供的resolveinstancemethod:方法。在c函数中不能直接使用实例变量,需要将objc对象self转成c中的结构体,因此在person类同样需要显式声明实例变量而且访问级别是@public,为了隐藏该实例变量,将声明放在扩展(extension)中
#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
总结以上,@dynamic的作用就是禁止编译器为@property产生setter和getter方法,有两种办法实现setter和getter方法:1)自己提供setter和getter方法;2)方法动态决议(dynamicmethod resolution)。
其它类似信息

推荐信息