介绍@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)。

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

本文分析了2025年的前四个JavaScript框架(React,Angular,Vue,Susve),比较了它们的性能,可伸缩性和未来前景。 尽管由于强大的社区和生态系统,所有这些都保持占主导地位,但它们的相对人口

本文讨论了使用咖啡因和Guava缓存在Java中实施多层缓存以提高应用程序性能。它涵盖设置,集成和绩效优势,以及配置和驱逐政策管理最佳PRA

Node.js 20通过V8发动机改进可显着提高性能,特别是更快的垃圾收集和I/O。 新功能包括更好的WebSembly支持和精制的调试工具,提高开发人员的生产率和应用速度。

Java的类上载涉及使用带有引导,扩展程序和应用程序类负载器的分层系统加载,链接和初始化类。父代授权模型确保首先加载核心类别,从而影响自定义类LOA

本文介绍了SnakeyAml中的CVE-2022-1471漏洞,这是一个允许远程代码执行的关键缺陷。 它详细介绍了如何升级春季启动应用程序到Snakeyaml 1.33或更高版本的降低风险,强调了依赖性更新

本文使用lambda表达式,流API,方法参考和可选探索将功能编程集成到Java中。 它突出显示了通过简洁性和不变性改善代码可读性和可维护性等好处

本文讨论了使用Maven和Gradle进行Java项目管理,构建自动化和依赖性解决方案,以比较其方法和优化策略。
