@synthesize vs @dynamic, sự khác biệt là gì?


Câu trả lời:


744

@synthesize sẽ tạo các phương thức getter và setter cho thuộc tính của bạn. @dynamic chỉ cho trình biên dịch biết rằng các phương thức getter và setter được thực hiện không phải bởi chính lớp đó mà ở một nơi khác (như siêu lớp hoặc sẽ được cung cấp trong thời gian chạy).

Sử dụng cho @dynamic, ví dụ như với các lớp con của NSManagedObject(CoreData) hoặc khi bạn muốn tạo một ổ cắm cho một thuộc tính được xác định bởi một siêu lớp không được xác định là một ổ cắm.

@dynamic cũng có thể được sử dụng để ủy thác trách nhiệm triển khai các bộ truy cập. Nếu bạn tự triển khai các hàm truy cập trong lớp thì thông thường bạn không sử dụng @dynamic.

Siêu hạng:

@property (nonatomic, retain) NSButton *someButton;
...
@synthesize someButton;

Phân lớp:

@property (nonatomic, retain) IBOutlet NSButton *someButton;
...
@dynamic someButton;

25
không đúng 100%; động là mặc định nếu bạn không đặt @synthesize hoặc @dynamic. chỉ định @dynamic chỉ có nghĩa là bạn chịu trách nhiệm triển khai đúng các bộ truy cập tài sản dựa trên chữ ký của tờ khai tài sản.
Kevlar

68
Không thực sự, @dynamic có nghĩa là trách nhiệm thực hiện các bộ truy cập được ủy quyền. Nếu bạn tự triển khai các hàm truy cập trong lớp thì thông thường bạn không sử dụng @dynamic.
deatherikh

2
Tôi đã gặp NSUnknownKeyExceptionlỗi với thuộc tính động của mình khi xóa @synthesizedòng (Xcode 3.2 đang báo lỗi cho tôi b / c Tôi không có ivar phù hợp với @property của tôi). Thêm @dynamicsửa lỗi - biên dịch và chạy tốt ngay bây giờ. Cảm ơn!
pix0r

4
Xin lỗi, mua cái này là hoàn toàn sai. @dynamic nói rằng các bộ truy cập được giải quyết trong thời gian chạy, trừ khi chúng được khai báo trong lớp hoặc siêu lớp (không phải ở nơi nào khác). Bạn có thể đọc tài liệu dành cho nhà phát
triển.apple.com / l Library / mac / document / cocoa / conceptionual / Giả

5
Kevlar: không. Trong ObjC hiện đại, @propertycác vật phẩm không có @synthesizehoặc không @dynamicđược tổng hợp tự động. Đối với mỗi thuộc tính, một ivar có dấu gạch dưới hàng đầu, ví dụ _propertyNamesẽ được tạo, cùng với getter và setter thích hợp.
Dave R

212

Hãy xem bài viết này ; trong tiêu đề "Phương thức được cung cấp khi chạy":

Một số bộ truy cập được tạo động khi chạy, chẳng hạn như một số bộ truy cập được sử dụng trong lớp NSManagedObject của CoreData. Nếu bạn muốn khai báo và sử dụng các thuộc tính cho các trường hợp này, nhưng muốn tránh cảnh báo về các phương thức bị thiếu trong thời gian biên dịch, bạn có thể sử dụng lệnh @dynamic thay vì @synthesize.

...

Sử dụng chỉ thị @dynamic về cơ bản cho trình biên dịch "đừng lo lắng về điều đó, một phương pháp đang được thực hiện."

Mặt @synthesizekhác, lệnh này tạo ra các phương thức truy cập cho bạn tại thời điểm biên dịch (mặc dù như đã lưu ý trong phần "Trộn các bộ truy cập tổng hợp và tùy chỉnh", nó linh hoạt và không tạo ra các phương thức cho bạn nếu được triển khai).


27
Đây là người đàn ông đúng đắn hơn. Câu trả lời này là câu trả lời duy nhất nói về các phương thức được tạo trong thời gian chạy, dường như thực sự nắm bắt được tinh thần hơn rất nhiều so với các bình chọn hàng đầu của atm
bobobobo

30

Như những người khác đã nói, nói chung, bạn sử dụng @synthesize để trình biên dịch tạo ra các getters và / hoặc cài đặt cho bạn và @dynamic nếu bạn sẽ tự viết chúng.

Có một sự tinh tế khác chưa được đề cập: @synthesize sẽ cho phép bạn tự cung cấp một triển khai, kể cả getter hoặc setter. Điều này hữu ích nếu bạn chỉ muốn triển khai getter cho một số logic bổ sung, nhưng hãy để trình biên dịch tạo setter (mà đối với các đối tượng, thường phức tạp hơn một chút để tự viết).

Tuy nhiên, nếu bạn viết một triển khai cho trình truy cập @ tổng hợp thì nó vẫn phải được hỗ trợ bởi một trường thực (ví dụ: nếu bạn viết, -(int) getFoo();bạn phải có một int foo;trường). Nếu giá trị đang được sản xuất bởi một thứ khác (ví dụ: được tính từ các trường khác) thì bạn phải sử dụng @dynamic.


2
+1 để đề cập đến sự khác biệt quan trọng: @dynamic cho phép bạn tạo các bộ truy cập cho các biến không được xác định trong giao diện lớp của bạn và thông qua hướng nội.
mahboudz

24
"Và @dynamicnếu bạn định tự viết chúng" Không, bạn KHÔNG sử dụng động nếu bạn tự viết chúng. @dynamictắt trình kiểm tra trình biên dịch để đảm bảo bạn đã triển khai chúng. Nếu bạn tự thực hiện chúng, bạn muốn trình biên dịch kiểm tra.
user102008

14

@dynamic thường được sử dụng (như đã nói ở trên) khi một thuộc tính đang được tạo động khi chạy. NSManagedObject thực hiện điều này (tại sao tất cả các thuộc tính của nó là động) - loại bỏ một số cảnh báo của trình biên dịch.

Để có cái nhìn tổng quan về cách tạo các thuộc tính một cách linh hoạt (không có NSManagedObject và CoreData:, hãy xem: http://developer.apple.com/l Library / ios / # ocumentation / Coloa / Conceptionual / OcbCRCRGuide / Articles / ocrtDocateResolution apple_Vf / doc / uid / TP40008048-CH102-SW1


14

đây là ví dụ về @dynamic

#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\n", [book.title UTF8String], [book.author UTF8String]);
    book.title = @"1984";
    book.author = @"George Orwell";
    printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);

   [book release];
   [pool release];
   return 0;
}

10

Theo tài liệu:

https://developer.apple.com/l Library / mac / document / cocoa / conception

@dynamic cho trình biên dịch biết rằng các phương thức truy cập được cung cấp trong thời gian chạy.

Với một chút điều tra, tôi phát hiện ra rằng việc cung cấp các phương thức truy cập sẽ ghi đè chỉ thị @dynamic.

@synthesize bảo trình biên dịch tạo các trình truy cập đó cho bạn (getter và setter)

@property nói với trình biên dịch rằng các bộ truy cập sẽ được tạo và có thể được truy cập bằng ký hiệu dấu chấm hoặc [thông báo đối tượng]


6

Một điều muốn thêm là nếu một thuộc tính được khai báo là @dynamic thì nó sẽ không chiếm bộ nhớ (tôi đã xác nhận với công cụ phân bổ). Một hậu quả là bạn có thể khai báo tài sản trong danh mục lớp.


Nếu tôi ghi đè một trình thiết lập thuộc tính trong một danh mục và làm cho nó động, điều này có đảm bảo ghi đè sẽ được sử dụng trong thời gian chạy chứ không phải trình thiết lập của lớp cha không? Từ tài liệu của Apple: "Nếu tên của một phương thức được khai báo trong một danh mục giống như một phương thức trong lớp gốc ... thì hành vi không được xác định là việc sử dụng phương thức nào được sử dụng trong thời gian chạy."
David James

Không, tôi nghĩ rằng hành vi vẫn chưa được xác định. Làm cho thuộc tính trong danh mục động không thay đổi mức ưu tiên thời gian chạy của phương thức setter.
Yingpei Zeng

3

Theo tài liệu của Apple.

Bạn sử dụng @synthesizecâu lệnh trong khối triển khai của lớp để báo cho trình biên dịch tạo các triển khai khớp với đặc tả mà bạn đã đưa ra trong @propertykhai báo.

Bạn sử dụng @dynamiccâu lệnh để báo cho trình biên dịch loại bỏ cảnh báo nếu nó không thể tìm thấy việc triển khai các phương thức truy cập được chỉ định bởi một @propertykhai báo.

Thêm thông tin:-

https://developer.apple.com/l Library / ios / document / General / Contualual / DevPedia-ColoaCore / DeclaredProperty.html

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.