@synthesize vs @dynamic, apa perbedaannya?

Jawaban:

744

@synthesize akan menghasilkan metode pengambil dan penyetel untuk properti Anda. @dynamic hanya memberitahu kompiler bahwa metode pengambil dan penyetel diimplementasikan bukan oleh kelas itu sendiri tetapi di tempat lain (seperti superclass atau akan disediakan saat runtime).

Penggunaan untuk @dynamic misalnya dengan subkelas NSManagedObject(CoreData) atau ketika Anda ingin membuat outlet untuk properti yang ditentukan oleh superclass yang tidak didefinisikan sebagai outlet.

@dynamic juga dapat digunakan untuk mendelegasikan tanggung jawab mengimplementasikan accessors. Jika Anda menerapkan accessors sendiri di dalam kelas maka Anda biasanya tidak menggunakan @dynamic.

Kelas super:

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

Subkelas:

@property (nonatomic, retain) IBOutlet NSButton *someButton;
...
@dynamic someButton;
diederikh
sumber
25
tidak 100% benar; dinamis adalah default jika Anda tidak mengatur @sintesize atau @dynamic. menetapkan @dynamic semata-mata berarti bahwa Anda bertanggung jawab untuk mengimplementasikan dengan tepat pengakses properti berdasarkan tanda tangan dari pernyataan properti.
Kevlar
68
Tidak juga, @dynamic berarti tanggung jawab implementasi accessors didelegasikan. Jika Anda menerapkan accessors sendiri di dalam kelas maka Anda biasanya tidak menggunakan @dynamic.
diederikh
2
Saya mendapatkan NSUnknownKeyExceptionkesalahan dengan properti dinamis saya ketika saya menghapus @synthesizebaris (Xcode 3.2 memberi saya kesalahan b / c saya tidak punya ivar yang cocok untuk @property saya). Menambahkan @dynamicmemperbaiki masalah - kompilasi dan berjalan dengan baik sekarang. Terima kasih!
Pix0r
4
Maaf, beli ini sepenuhnya salah. @dynamic memberi tahu bahwa pengakses diselesaikan pada saat runtime, kecuali jika dinyatakan di kelas atau superclass (tidak di tempat lain). Anda dapat membaca dokumentasi pengembang.apple.com/library/mac/documentation/cocoa/conceptual/…
user1447414
5
Kevlar: tidak. Di ObjC modern, @propertyitem yang tidak memiliki @synthesizeatau @dynamicakan disintesis secara otomatis. Untuk setiap properti, sebuah ivar dengan garis bawah utama, misalnya _propertyNameakan dibuat, bersama dengan pengambil dan penyetel yang sesuai.
Dave R
212

Lihatlah artikel ini ; di bawah judul "Metode yang disediakan saat runtime":

Beberapa accessor dibuat secara dinamis saat runtime, seperti yang digunakan di kelas NSManagedObject CoreData. Jika Anda ingin mendeklarasikan dan menggunakan properti untuk kasus-kasus ini, tetapi ingin menghindari peringatan tentang metode yang hilang pada waktu kompilasi, Anda dapat menggunakan direktif @dynamic alih-alih @sintesis.

...

Menggunakan direktif @dynamic pada dasarnya memberitahu kompiler "jangan khawatir tentang hal itu, metode sedang dalam perjalanan."

The @synthesizedirektif, di sisi lain, menghasilkan metode accessor untuk Anda pada waktu kompilasi (meskipun seperti yang tercantum dalam bagian "Pencampuran disintesis dan Custom Accessors" itu adalah fleksibel dan tidak menghasilkan metode untuk Anda jika salah diimplementasikan).

Alex Rozanski
sumber
27
Ini adalah manusia yang lebih benar. Jawaban ini adalah satu-satunya jawaban yang berbicara tentang metode yang diciptakan pada saat runtime, yang tampaknya benar-benar menangkap semangat lebih banyak dari atas sebagai ans atm
bobobobo
30

Seperti yang orang lain katakan, secara umum Anda menggunakan @synthesize untuk membuat kompiler menghasilkan getter dan / atau pengaturan untuk Anda, dan @dynamic jika Anda ingin menulisnya sendiri.

Ada kehalusan lain yang belum disebutkan: @synthesize akan membiarkan Anda memberikan implementasi sendiri, baik dari pengambil atau penyetel. Ini berguna jika Anda hanya ingin mengimplementasikan pengambil untuk beberapa logika tambahan, tetapi biarkan kompiler menghasilkan setter (yang, untuk objek, biasanya sedikit lebih rumit untuk menulis sendiri).

Namun, jika Anda menulis implementasi untuk pengakses @ synthesize'd itu masih harus didukung oleh bidang nyata (misalnya, jika Anda menulis -(int) getFoo();Anda harus memiliki int foo;bidang). Jika nilai sedang diproduksi oleh sesuatu yang lain (misalnya dihitung dari bidang lain) maka Anda harus menggunakan @dynamic.

philsquared
sumber
2
+1 untuk menyebutkan perbedaan penting: @dynamic memungkinkan Anda membuat accessor untuk varaibles yang tidak didefinisikan di antarmuka kelas Anda dan melalui introspeksi.
mahboudz
24
"dan @dynamicjika Anda akan menulisnya sendiri" Tidak, Anda TIDAK menggunakan dinamis jika Anda menulisnya sendiri. @dynamicmematikan pemeriksaan kompiler untuk memastikan Anda menerapkannya. Jika Anda menerapkannya sendiri, Anda ingin kompilator memeriksa.
user102008
14

@dynamic biasanya digunakan (seperti yang telah dikatakan di atas) ketika sebuah properti sedang dibuat secara dinamis saat runtime. NSManagedObject melakukan ini (mengapa semua propertinya dinamis) - yang menekan beberapa peringatan kompiler.

Untuk gambaran umum yang baik tentang cara membuat properti secara dinamis (tanpa NSManagedObject dan CoreData :, lihat: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#//// apple_ref / doc / uid / TP40008048-CH102-SW1

mifortin
sumber
14

di sini adalah contoh @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;
}
cermin
sumber
10

Sesuai dokumentasi:

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

@dynamic memberi tahu kompiler bahwa metode accessor disediakan saat runtime.

Dengan sedikit penyelidikan saya menemukan bahwa menyediakan metode accessor mengesampingkan direktif @dynamic.

@synthesize memberitahu kompiler untuk membuat pengakses tersebut untuk Anda (pengambil dan penyetel)

@ properti memberitahu kompiler bahwa accessors akan dibuat, dan yang dapat diakses dengan notasi titik atau [pesan objek]

pengguna1447414
sumber
6

Satu hal yang ingin ditambahkan adalah bahwa jika properti dideklarasikan sebagai @dynamic tidak akan menempati memori (saya dikonfirmasi dengan instrumen alokasi). Konsekuensinya adalah Anda dapat mendeklarasikan properti dalam kategori kelas.

Yingpei Zeng
sumber
Jika saya menimpa setter properti dalam kategori dan membuatnya dinamis, apakah ini menjamin penggantian akan digunakan saat runtime dan bukan setter kelas induk? Dari Apple docs: "Jika nama metode yang dideklarasikan dalam kategori adalah sama dengan metode di kelas asli ... perilaku tidak terdefinisi tentang implementasi metode mana yang digunakan saat runtime."
David James
Tidak, saya pikir perilakunya masih tidak jelas. Menjadikan properti dalam kategori dinamis tidak mengubah prioritas runtime metode penyetel properti.
Yingpei Zeng
3

Sesuai dokumentasi Apple.

Anda menggunakan @synthesizepernyataan di blok implementasi kelas untuk memberi tahu kompiler untuk membuat implementasi yang cocok dengan spesifikasi yang Anda berikan dalam @propertydeklarasi.

Anda menggunakan @dynamicpernyataan untuk memberi tahu kompiler untuk menekan peringatan jika tidak dapat menemukan implementasi metode accessor yang ditentukan oleh @propertydeklarasi.

Info lebih lanjut:-

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

arango_86
sumber