Apa perbedaan antara id
dan void *
?
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
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).id
ditanggapi. Sebuahid
dapat dengan mudah merujuk ke instance kelas yang tidak inheren dariNSObject
. 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
danClass
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*
atauid<NSObject>
dalam preferensiid
, yang setidaknya mengkonfirmasi bahwa objek yang dikembalikan adalah objek Kakao, sehingga Anda dapat dengan aman menggunakan metode seperti mempertahankan / melepaskan / melepaskan otomatis di atasnya.sumber
Often you should use NSObject*
bukanid
. Dengan menentukanNSObject*
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, jadiid
lebih baik. Tentu Anda bisa lebih spesifik dengan misalnya mengatakanid<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.sumber
id
adalah pointer ke objek Objective-C.void *
adalah pointer ke apa pun . Anda dapat menggunakannyavoid *
sebagai gantiid
, 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 .
sumber
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. dasarKode 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.
sumber
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
sumber
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 mengonversivoid *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 .sumber