@synthesize vs @dynamic ความแตกต่างคืออะไร


คำตอบ:


744

@synthesize จะสร้างเมธอด getter และ setter สำหรับคุณสมบัติของคุณ @Dynamic เพียงบอกคอมไพเลอร์ว่าเมธอด getter และ setter นั้นไม่ได้ถูกนำไปใช้โดยคลาส แต่เป็นที่อื่น (เช่นซูเปอร์คลาส

ใช้สำหรับ @dynamic เป็นเช่นกับ subclasses ของNSManagedObject(CoreData) หรือเมื่อคุณต้องการสร้างเต้าเสียบสำหรับคุณสมบัติที่กำหนดโดย superclass ที่ไม่ได้กำหนดเป็นเต้าเสียบ

@dynamic สามารถใช้เพื่อมอบหมายความรับผิดชอบในการใช้งาน accessors ถ้าคุณใช้ accessors ด้วยตัวคุณเองในคลาสคุณจะไม่ใช้ @dynamic

ชั้นพิเศษ:

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

ซับคลาส:

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

25
ไม่ถูกต้อง 100%; แบบไดนามิกเป็นค่าเริ่มต้นหากคุณไม่ได้ตั้งค่า @synthesize หรือ @dynamic การระบุ @dynamic เพียง แต่หมายความว่าคุณต้องรับผิดชอบในการใช้งานตัวเข้าถึงคุณสมบัติอย่างถูกต้องตามลายเซ็นของการประกาศคุณสมบัติ
464 Kevlar Kevlar

68
ไม่ได้จริงๆ @dynamic หมายถึงความรับผิดชอบในการใช้งาน accessors ที่ได้รับมอบหมาย ถ้าคุณใช้ accessors ด้วยตัวคุณเองในคลาสคุณจะไม่ใช้ @dynamic
diederikh

2
ฉันได้รับNSUnknownKeyExceptionข้อผิดพลาดกับคุณสมบัติแบบไดนามิกของฉันเมื่อฉันลบ@synthesizeบรรทัด (Xcode 3.2 ทำให้ฉันมีข้อผิดพลาด b / c ฉันไม่มี ivar ที่ตรงกับ @property ของฉัน) การเพิ่ม@dynamicแก้ไขปัญหา - รวบรวมและทำงานได้ดีในขณะนี้ ขอบคุณ!
pix0r

4
ขออภัยซื้อนี่ผิดทั้งหมด @dynamic บอกว่า accessors ได้รับการแก้ไขที่รันไทม์เว้นแต่พวกเขาจะประกาศใน class หรือ superclass (ไม่ใช่ที่อื่น) คุณสามารถอ่านเอกสารdeveloper.apple.com/library/mac/documentation/cocoa/conceptual/?hl=th
1447414

5
เคฟลาร์: ไม่ ใน ObjC สมัยใหม่@propertyรายการที่ไม่มี@synthesizeและ@dynamicจะไม่ถูกสังเคราะห์โดยอัตโนมัติ สำหรับทรัพย์สินแต่ละรายการ_propertyNameจะมีการสร้างivar ที่มีเครื่องหมายขีดเส้นใต้นำพร้อมกับตัวคั่นและตัวตั้งค่าที่เหมาะสม
Dave R

212

ลองดูที่บทความนี้ ; ภายใต้หัวข้อ "วิธีการที่มีให้ ณ รันไทม์":

accessors บางตัวถูกสร้างขึ้นแบบไดนามิก ณ รันไทม์เช่นบางรายการที่ใช้ในคลาส NSManagedObject ของ CoreData หากคุณต้องการประกาศและใช้คุณสมบัติสำหรับกรณีเหล่านี้ แต่ต้องการหลีกเลี่ยงคำเตือนเกี่ยวกับวิธีการที่ขาดหายไปในเวลารวบรวมคุณสามารถใช้ @dynamic directive แทน @synthesize

...

การใช้ @dynamic directive เป็นหลักบอกคอมไพเลอร์ "ไม่ต้องกังวลกับมันวิธีการกำลังจะมาถึง"

ในทางกลับกัน@synthesizeคำสั่งจะสร้างวิธีการเข้าถึงสำหรับคุณ ณ เวลารวบรวม (แม้ว่าดังที่ระบุไว้ในส่วน "การผสมการสังเคราะห์และการเข้าถึงแบบกำหนดเอง" จะมีความยืดหยุ่นและไม่ได้สร้างวิธีการสำหรับคุณหากมีการใช้งาน)


27
นี่คือชายผู้แก้ไขที่ morer คำตอบนี้เป็นคำตอบเดียวที่พูดคุยเกี่ยวกับวิธีการสร้างที่รันไทม์ซึ่งจริงๆดูเหมือนว่าจะจับวิญญาณมากขึ้นกว่าด้านบนได้รับการโหวต ans ตู้เอทีเอ็ม
bobobobo

30

ตามที่คนอื่นพูดโดยทั่วไปคุณใช้ @synthesize เพื่อให้คอมไพเลอร์สร้าง getters และ / หรือการตั้งค่าสำหรับคุณและ @dynamic หากคุณจะเขียนด้วยตนเอง

มีความละเอียดอ่อนอื่นที่ยังไม่ได้กล่าวถึง: @synthesize จะช่วยให้คุณสามารถดำเนินการได้ด้วยตัวเองไม่ว่าจะเป็นผู้ทะเยอทะยานหรือผู้ตั้งตัว สิ่งนี้มีประโยชน์หากคุณต้องการใช้ getter สำหรับตรรกะพิเศษบางอย่างเท่านั้น แต่ให้คอมไพเลอร์สร้าง setter (ซึ่งสำหรับวัตถุมักจะซับซ้อนกว่าเล็กน้อยในการเขียนตัวเอง)

อย่างไรก็ตามหากคุณเขียนการนำไปใช้งานสำหรับ @ synthesize'd accessor นั้นจะต้องสำรองข้อมูลโดยฟิลด์จริง (เช่นถ้าคุณเขียน-(int) getFoo();คุณต้องมีint foo;ฟิลด์) หากค่ากำลังถูกผลิตโดยอย่างอื่น (เช่นคำนวณจากเขตข้อมูลอื่น) คุณต้องใช้ @dynamic


2
+1 สำหรับการกล่าวถึงความแตกต่างที่สำคัญ: @dynamic ช่วยให้คุณสร้าง accessors สำหรับ varaibles ที่ไม่ได้กำหนดไว้ในอินเทอร์เฟซของคลาสและผ่านการวิปัสสนา
mahboudz

24
"และ@dynamicถ้าคุณจะเขียนด้วยตนเอง" ไม่คุณจะไม่ใช้ไดนามิกหากคุณเขียนเอง @dynamicปิดการตรวจสอบคอมไพเลอร์เพื่อให้แน่ใจว่าคุณได้ติดตั้งแล้ว หากคุณติดตั้งด้วยตัวคุณเองคุณต้องการให้คอมไพเลอร์ตรวจสอบ
user102008

14

โดยทั่วไปแล้ว @dynamic จะใช้ (ดังที่ได้กล่าวไว้ข้างต้น) เมื่อคุณสมบัติถูกสร้างขึ้นแบบไดนามิกที่รันไทม์ NSManagedObject ทำสิ่งนี้ (เหตุใดคุณสมบัติทั้งหมดจึงเป็นแบบไดนามิก) - ซึ่งไม่แสดงคำเตือนของคอมไพเลอร์

สำหรับภาพรวมที่ดีเกี่ยวกับวิธีการสร้างคุณสมบัติแบบไดนามิก (โดยไม่มี NSManagedObject และ CoreData: โปรดดู: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#// apple_ref / doc / UID / TP40008048-CH102-SW1


14

นี่คือตัวอย่างของ @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

ตามเอกสาร:

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html

@dynamic บอกคอมไพเลอร์ว่ามีการระบุวิธีการเข้าถึงที่รันไทม์

จากการตรวจสอบเล็กน้อยฉันพบว่าการให้วิธีการเข้าถึงแทนที่ @dynamic directive

@synthesize บอกคอมไพเลอร์เพื่อสร้าง accessors สำหรับคุณ (getter และ setter)

@property บอกคอมไพเลอร์ว่า accessors จะถูกสร้างขึ้นและสามารถเข้าถึงได้ด้วยเครื่องหมายจุดหรือ [ข้อความวัตถุ]


6

สิ่งหนึ่งที่ต้องการเพิ่มคือถ้ามีการประกาศคุณสมบัติเป็น @dynamic มันจะไม่ใช้หน่วยความจำ (ฉันยืนยันด้วยเครื่องมือการจัดสรร) ผลลัพธ์คือคุณสามารถประกาศคุณสมบัติในหมวดหมู่คลาส


หากฉันแทนที่ตัวตั้งค่าคุณสมบัติในหมวดหมู่และทำให้เป็นแบบไดนามิกสิ่งนี้จะรับประกันว่าการแทนที่จะถูกใช้ในขณะใช้งานจริงไม่ใช่ตัวตั้งค่าของคลาสพาเรนต์หรือไม่ จากเอกสารของ Apple: "หากชื่อของวิธีการที่ประกาศในหมวดหมู่นั้นเหมือนกับวิธีการในชั้นเรียนดั้งเดิม ... พฤติกรรมไม่ได้กำหนดว่าจะใช้วิธีการใดในการใช้งานจริง"
David James

ไม่ฉันคิดว่าพฤติกรรมนี้ยังไม่ได้กำหนด การทำให้คุณสมบัติเป็นหมวดหมู่แบบไดนามิกจะไม่เปลี่ยนลำดับความสำคัญรันไทม์ของเมธอดตัวตั้งค่าคุณสมบัติ
Yingpei Zeng

3

ตามเอกสารของ Apple

คุณใช้@synthesizeคำสั่งในบล็อกการใช้งานของคลาสเพื่อบอกคอมไพเลอร์เพื่อสร้างการใช้งานที่ตรงกับข้อกำหนดที่คุณให้ไว้ในการ@propertyประกาศ

คุณใช้@dynamicคำสั่งเพื่อบอกคอมไพเลอร์เพื่อยับยั้งการเตือนหากไม่พบการใช้งานวิธีการเข้าถึงที่ระบุโดยการ@propertyประกาศ

ข้อมูลเพิ่มเติม:-

https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/DeclaredProperty.html

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.