Jawaban:
void *
berarti "referensi ke sejumlah memori acak dengan isi yang tidak diketik / tidak dikenal"
id
berarti "referensi ke beberapa objek Objective-C acak kelas tidak diketahui"
Ada perbedaan semantik tambahan:
Di bawah Hanya GC atau mode yang Didukung GC, kompiler akan memancarkan hambatan penulisan untuk referensi tipe id
, tetapi tidak untuk tipe void *
. Ketika mendeklarasikan struktur, ini bisa menjadi perbedaan kritis. Mendeklarasikan iVars seperti void *_superPrivateDoNotTouch;
akan menyebabkan menuai prematur objek jika _superPrivateDoNotTouch
sebenarnya sebuah objek. Jangan lakukan itu.
mencoba memohon metode pada referensi void *
tipe akan membuat peringatan kompiler.
mencoba memohon metode pada id
tipe hanya akan memperingatkan jika metode yang dipanggil belum dideklarasikan dalam @interface
deklarasi apa pun yang dilihat oleh kompiler.
Dengan demikian, seseorang tidak boleh merujuk ke objek sebagai a void *
. Demikian pula, seseorang harus menghindari menggunakan id
variabel yang diketik untuk merujuk ke objek. Gunakan referensi diketik kelas paling spesifik yang Anda bisa. Bahkan NSObject *
lebih baik daripadaid
karena kompiler dapat, paling tidak, memberikan validasi yang lebih baik dari pemanggilan metode terhadap referensi itu.
Penggunaan yang umum dan valid dari void *
adalah sebagai referensi data buram yang dilewatkan melalui beberapa API lainnya.
Pertimbangkan sortedArrayUsingFunction: context:
metode NSArray
:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
Fungsi penyortiran akan dinyatakan sebagai:
NSInteger mySortFunc(id left, id right, void *context) { ...; }
Dalam hal ini, NSArray hanya meneruskan apa pun yang Anda berikan sebagai context
argumen untuk metode melalui sebagaicontext
argumen. Ini adalah kumpulan data ukuran pointer yang buram, sejauh menyangkut NSArray, dan Anda bebas menggunakannya untuk tujuan apa pun yang Anda inginkan.
Tanpa fitur tipe penutupan dalam bahasa, ini adalah satu-satunya cara untuk membawa sebongkah data dengan fungsi. Contoh; jika Anda ingin mySortFunc () disortir secara kondisional sebagai case-sensitive atau case-insensitive, sementara juga masih aman untuk thread, Anda akan melewatkan indikator case-sensitive dalam konteks, kemungkinan mencari di jalan masuk dan jalan keluar.
Rapuh dan rawan kesalahan, tetapi satu-satunya cara.
Blok memecahkan ini - Blok adalah penutupan untuk C. Mereka tersedia di Dentang - http://llvm.org/ dan meresap di Snow Leopard ( http://developer.apple.com/library/ios/documentation/Performance /Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf ).
id
ditanggapi. Sebuah id
dapat dengan mudah merujuk ke instance kelas yang tidak inheren dari NSObject
. Namun, secara praktis, pernyataan Anda paling cocok dengan perilaku dunia nyata; Anda tidak dapat mencampur <NSObject>
kelas yang tidak menerapkan dengan API Foundation dan melangkah terlalu jauh, itu sudah pasti!
id
dan Class
jenis diperlakukan sebagai pointer objek yang dapat dipertahankan di bawah ARC. Jadi anggapan itu benar setidaknya di bawah ARC.
id adalah pointer ke objek C objektif, di mana void * adalah pointer ke apa pun.
id juga mematikan peringatan terkait dengan memanggil mthod yang tidak dikenal, jadi misalnya:
[(id)obj doSomethingWeirdYouveNeverHeardOf];
tidak akan memberikan peringatan biasa tentang metode yang tidak diketahui. Itu tentu saja akan menimbulkan pengecualian pada saat run time kecuali obj tidak ada atau benar-benar mengimplementasikan metode itu.
Seringkali Anda harus menggunakan NSObject*
atau id<NSObject>
dalam preferensi id
, yang setidaknya mengkonfirmasi bahwa objek yang dikembalikan adalah objek Kakao, sehingga Anda dapat dengan aman menggunakan metode seperti mempertahankan / melepaskan / melepaskan otomatis di atasnya.
Often you should use NSObject*
bukan id
. Dengan menentukan NSObject*
Anda sebenarnya secara eksplisit mengatakan bahwa objek tersebut adalah NSObject. Setiap pemanggilan metode ke objek akan menghasilkan peringatan, tetapi tidak ada pengecualian runtime selama objek itu memang merespons pemanggilan metode. Peringatan itu jelas menjengkelkan, jadi id
lebih baik. Tentu Anda bisa lebih spesifik dengan misalnya mengatakan id<MKAnnotation>
, yang dalam hal ini berarti apa pun objeknya, harus sesuai dengan protokol MKAnnotation.
Jika suatu metode memiliki tipe pengembalian id
Anda dapat mengembalikan objek Objective-C.
void
berarti, metode ini tidak akan mengembalikan apa pun.
void *
hanyalah sebuah pointer. Anda tidak akan dapat mengedit konten di alamat yang ditunjuk oleh pointer.
id
adalah pointer ke objek Objective-C. void *
adalah pointer ke apa pun . Anda dapat menggunakannya void *
sebagai ganti id
, tetapi tidak disarankan karena Anda tidak akan pernah mendapatkan peringatan kompiler untuk apa pun.
Anda mungkin ingin melihat stackoverflow.com/questions/466777/whats-the-difference-between-dclaring-a-variable-id-and-nsobject dan unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs -id.html .
void *
variabel yang diketik pasti bisa menjadi target pemanggilan metode - ini peringatan, bukan kesalahan. Tidak hanya itu, Anda dapat melakukan ini: int i = (int)@"Hello, string!";
dan menindaklanjuti dengan: printf("Sending to an int: '%s'\n", [i UTF8String]);
. Ini peringatan, bukan kesalahan (dan tidak disarankan, atau portabel). Tapi alasan mengapa Anda dapat melakukan hal-hal ini adalah semua C. dasar
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
Kode di atas adalah dari objc.h, jadi sepertinya id adalah turunan dari objc_object struct dan isa pointer dapat mengikat dengan objek Objective C Class apa pun, sedangkan void * hanyalah pointer yang tidak diketik.
Pemahaman saya adalah bahwa id merepresentasikan pointer ke objek sementara void * dapat menunjuk ke sesuatu yang benar-benar, asalkan Anda kemudian melemparkannya ke jenis yang ingin Anda gunakan sebagai
Selain apa yang sudah dikatakan, ada perbedaan antara objek dan pointer yang terkait dengan koleksi. Misalnya, jika Anda ingin memasukkan sesuatu ke NSArray, Anda memerlukan objek (dari tipe "id"), dan Anda tidak dapat menggunakan pointer data mentah di sana (dari tipe "void *"). Anda dapat menggunakan [NSValue valueWithPointer:rawData]
untuk mengonversi void *rawDdata
ke tipe "id" untuk menggunakannya di dalam koleksi. Secara umum "id" lebih fleksibel dan memiliki lebih banyak semantik yang terkait dengan objek yang melekat padanya. Ada lebih banyak contoh yang menjelaskan tipe id dari Objective C di sini .
id
diasumsikan merespons-retain
dan-release
, sedangkan avoid*
benar-benar buram bagi callee. Anda tidak dapat meneruskan pointer sewenang-wenang ke-performSelector:withObject:afterDelay:
(itu mempertahankan objek), dan Anda tidak dapat berasumsi bahwa+[UIView beginAnimations:context:]
akan mempertahankan konteks (delegasi animasi harus mempertahankan kepemilikan konteks; UIKit mempertahankan delegasi animasi).