关于C#:@synthesis vs@dynamic,有什么区别?

@synthesize vs @dynamic, what are the differences?

实施@property@dynamic@synthesize有什么区别?


@合成器将为您的属性生成getter和setter方法。@dynamic只是告诉编译器getter和setter方法不是由类本身实现的,而是在其他地方实现的(如超类或将在运行时提供)。

@dynamic的用法是,例如,使用NSManagedObject的子类(coredata),或者当您想要为一个未定义为outlet的超类所定义的属性创建一个outlet时。

@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."

另一方面,@synthesize指令在编译时为您生成访问器方法(尽管如"混合合成访问器和自定义访问器"部分所述,它是灵活的,如果实现了这两种方法,则不会为您生成方法)。


正如其他人所说,通常情况下,您使用@synthesis让编译器为您生成getter和/或设置,如果您要自己编写它们,则使用@dynamic。

还有一个尚未提到的微妙之处:@synthesis将允许您自己提供getter或setter的实现。如果您只想为一些额外的逻辑实现getter,但是让编译器生成setter(对于对象来说,通常自己编写要复杂一些),那么这很有用。

但是,如果您确实为@synthesis'd访问器编写了一个实现,它仍然必须由一个实字段支持(例如,如果您编写-(int) getFoo();,您必须有一个int foo;字段)。如果该值是由其他对象产生的(例如,从其他字段计算),则必须使用@dynamic。


以下是@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,它将不会占用内存(我用分配工具确认)。结果是您可以在类类别中声明属性。


根据苹果文件。

使用类的实现块中的@synthesize语句,告诉编译器创建与在@property声明中给出的规范相匹配的实现。

如果编译器找不到由@property声明指定的访问器方法的实现,可以使用@dynamic语句通知编译器取消警告。

更多信息:

https://developer.apple.com/library/ios/documentation/general/conceptive/devpedia-cocoacore/declaredproperty.html