@synthesize vs @dynamic, what are the differences?
实施
@合成器将为您的属性生成getter和setter方法。@dynamic只是告诉编译器getter和setter方法不是由类本身实现的,而是在其他地方实现的(如超类或将在运行时提供)。
@dynamic的用法是,例如,使用
@dynamic还可以用来委托实现访问器的职责。如果您自己在类中实现访问器,那么通常不使用@dynamic。
超级类:
1 2 3 | @property (nonatomic, retain) NSButton *someButton; ... @synthesize someButton; |
Subclass:
1 2 3 | @property (nonatomic, retain) IBOutlet NSButton *someButton; ... @dynamic someButton; |
看看这篇文章;在标题"运行时提供的方法"下:
Some accessors are created dynamically at runtime, such as certain ones used in CoreData's NSManagedObject class. If you want to declare and use properties for these cases, but want to avoid warnings about methods missing at compile time, you can use the @dynamic directive instead of @synthesize.
...
Using the @dynamic directive essentially tells the compiler"don't worry about it, a method is on the way."
另一方面,
正如其他人所说,通常情况下,您使用@synthesis让编译器为您生成getter和/或设置,如果您要自己编写它们,则使用@dynamic。
还有一个尚未提到的微妙之处:@synthesis将允许您自己提供getter或setter的实现。如果您只想为一些额外的逻辑实现getter,但是让编译器生成setter(对于对象来说,通常自己编写要复杂一些),那么这很有用。
但是,如果您确实为@synthesis'd访问器编写了一个实现,它仍然必须由一个实字段支持(例如,如果您编写
以下是@dynamic的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | #import <Foundation/Foundation.h> @interface Book : NSObject { NSMutableDictionary *data; } @property (retain) NSString *title; @property (retain) NSString *author; @end @implementation Book @dynamic title, author; - (id)init { if ((self = [super init])) { data = [[NSMutableDictionary alloc] init]; [data setObject:@"Tom Sawyer" forKey:@"title"]; [data setObject:@"Mark Twain" forKey:@"author"]; } return self; } - (void)dealloc { [data release]; [super dealloc]; } - (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:&obj atIndex:2]; [data setObject:obj forKey:key]; } else { NSString *obj = [data objectForKey:key]; [invocation setReturnValue:&obj]; } } @end int main(int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Book *book = [[Book alloc] init]; printf("%s is written by %s ", [book.title UTF8String], [book.author UTF8String]); book.title = @"1984"; book.author = @"George Orwell"; printf("%s is written by %s ", [book.title UTF8String], [book.author UTF8String]); [book release]; [pool release]; return 0; } |
@动态通常在运行时动态创建属性时使用(如上所述)。nsmanagedObject会这样做(为什么它的所有属性都是动态的),这会抑制一些编译器警告。
有关如何动态创建属性(不带nsmanagedObject和coredata)的良好概述,请参阅:http://developer.apple.com/library/ios/documentation/cocoa/conceptive/objcruntimeguide/articles/ocrtdynamicresolution.html//apple-ref/doc/uid/tp40008048-ch102-sw1
根据文件:
https://developer.apple.com/library/mac/documentation/cocoa/conceptive/objcruntimeguide/articles/ocrtdynamicresolution.html
@动态告诉编译器访问器方法是在运行时提供的。
经过一点调查,我发现提供访问器方法会重写@dynamic指令。
@合成器告诉编译器为您创建那些访问器(getter和setter)
@属性告诉编译器将创建访问器,并且可以使用点标记或[对象消息]访问访问器。
要添加的一点是,如果一个属性声明为@dynamic,它将不会占用内存(我用分配工具确认)。结果是您可以在类类别中声明属性。
根据苹果文件。
使用类的实现块中的
如果编译器找不到由
更多信息:
https://developer.apple.com/library/ios/documentation/general/conceptive/devpedia-cocoacore/declaredproperty.html