Sebagai pengembang Java yang membaca dokumentasi Objective-C 2.0 Apple: Saya ingin tahu apa artinya " mengirim pesan ke nil " - apalagi bagaimana sebenarnya itu berguna. Mengambil kutipan dari dokumentasi:
Ada beberapa pola di Kakao yang memanfaatkan fakta ini. Nilai yang dikembalikan dari pesan menjadi nihil mungkin juga valid:
- Jika metode mengembalikan objek, tipe penunjuk apa pun, skalar bilangan bulat apa pun yang ukurannya kurang dari atau sama dengan sizeof (void *), float, double, long double, atau long long, maka pesan yang dikirim ke nil mengembalikan 0 .
- Jika metode mengembalikan struct, seperti yang didefinisikan oleh Mac OS X ABI Function Call Guide untuk dikembalikan dalam register, maka pesan yang dikirim ke nil mengembalikan 0,0 untuk setiap bidang dalam struktur data. Tipe data struct lainnya tidak akan diisi dengan angka nol.
- Jika metode mengembalikan apa pun selain tipe nilai yang disebutkan di atas, nilai kembali dari pesan yang dikirim ke nil tidak ditentukan.
Apakah Java membuat otak saya tidak mampu membaca penjelasan di atas? Atau adakah sesuatu yang saya lewatkan yang akan membuat ini sejelas kaca?
Saya mendapatkan ide tentang pesan / penerima di Objective-C, saya hanya bingung tentang penerima yang kebetulan ada nil
.
objective-c
Ryan Delucchi
sumber
sumber
Jawaban:
Saya rasa ini bisa dijelaskan dengan contoh yang dibuat-buat. Katakanlah Anda memiliki metode di Java yang mencetak semua elemen dalam ArrayList:
Sekarang, jika Anda memanggil metode itu seperti: someObject.foo (NULL); Anda mungkin akan mendapatkan NullPointerException ketika mencoba mengakses daftar, dalam hal ini dalam panggilan ke list.size (); Sekarang, Anda mungkin tidak akan pernah memanggil someObject.foo (NULL) dengan nilai NULL seperti itu. Namun, Anda mungkin mendapatkan ArrayList Anda dari metode yang mengembalikan NULL jika mengalami beberapa kesalahan saat menghasilkan ArrayList seperti someObject.foo (otherObject.getArrayList ());
Tentu saja, Anda juga akan mendapat masalah jika melakukan hal seperti ini:
Sekarang, di Objective-C, kami memiliki metode yang setara:
Sekarang, jika kita memiliki kode berikut:
kami memiliki situasi yang sama di mana Java akan menghasilkan NullPointerException. Objek nil akan diakses pertama kali pada [anArray count] Namun, alih-alih melempar NullPointerException, Objective-C hanya akan mengembalikan 0 sesuai dengan aturan di atas, sehingga loop tidak akan berjalan. Namun, jika kita menyetel perulangan untuk menjalankan beberapa kali, maka pertama-tama kita mengirim pesan ke anArray di [anArray objectAtIndex: i]; Ini juga akan mengembalikan 0, tetapi karena objectAtIndex: mengembalikan pointer, dan pointer ke 0 adalah nil / NULL, NSLog akan diteruskan nil setiap kali melalui loop. (Meskipun NSLog adalah fungsi dan bukan metode, ia mencetak (null) jika meneruskan NSString nil.
Dalam beberapa kasus, lebih baik memiliki NullPointerException, karena Anda dapat langsung mengetahui bahwa ada sesuatu yang salah dengan program, tetapi kecuali Anda menangkap pengecualian, program akan macet. (Dalam C, mencoba untuk mendereferensi NULL dengan cara ini menyebabkan program macet.) Dalam Objective-C, itu malah menyebabkan perilaku run-time yang mungkin salah. Namun, jika Anda memiliki metode yang tidak rusak jika mengembalikan 0 / nil / NULL / struct zeroed, maka Anda tidak perlu memeriksa untuk memastikan objek atau parameternya nihil.
sumber
myObject->iVar
akan crash, tidak peduli apakah itu C dengan atau tanpa objek. (maaf untuk->
bukan lagi operasi Objective-C tapi sangat C-isme generik.Sebuah pesan
nil
tidak apa-apa dan kembalinil
,Nil
,NULL
,0
, atau0.0
.sumber
Semua postingan lainnya benar, tapi mungkin konsep itulah yang terpenting di sini.
Dalam panggilan metode Objective-C, referensi objek apa pun yang dapat menerima selektor adalah target yang valid untuk pemilih tersebut.
Ini menghemat BANYAK "apakah objek target tipe X?" kode - selama objek penerima mengimplementasikan selector, tidak ada bedanya kelas apa itu!
nil
adalah NSObject yang menerima pemilih apa pun - ia tidak melakukan apa - apa. Ini menghilangkan banyak kode "periksa nihil, jangan kirim pesan jika benar" juga. (Konsep "jika ia menerimanya, ia mengimplementasikannya" juga yang memungkinkan Anda untuk membuat protokol , yang agak mirip dengan antarmuka Java: deklarasi bahwa jika suatu kelas mengimplementasikan metode yang dinyatakan, maka ia sesuai dengan protokol.)Alasannya adalah untuk menghilangkan kode monyet yang tidak melakukan apa pun kecuali membuat kompiler senang. Ya, Anda mendapatkan overhead untuk satu pemanggilan metode lagi, tetapi Anda menghemat waktu programmer , yang merupakan sumber daya yang jauh lebih mahal daripada waktu CPU. Selain itu, Anda menghilangkan lebih banyak kode dan lebih banyak kompleksitas bersyarat dari aplikasi Anda.
Memperjelas downvoters: Anda mungkin berpikir ini bukan cara yang baik, tetapi bagaimana bahasa diterapkan, dan ini adalah idiom pemrograman yang direkomendasikan di Objective-C (lihat kuliah pemrograman iPhone Stanford).
sumber
Artinya adalah bahwa runtime tidak menghasilkan kesalahan saat objc_msgSend dipanggil pada pointer nil; sebaliknya ia mengembalikan beberapa nilai (sering kali berguna). Pesan yang mungkin memiliki efek samping tidak melakukan apa-apa.
Ini berguna karena sebagian besar nilai default lebih sesuai daripada kesalahan. Sebagai contoh:
Yaitu, nil tampaknya menjadi array kosong. Menyembunyikan referensi NSView nihil tidak melakukan apa pun. Berguna, ya?
sumber
Dalam kutipan dari dokumentasi, terdapat dua konsep yang berbeda - mungkin akan lebih baik jika dokumentasinya dibuat lebih jelas:
Yang pertama mungkin lebih relevan di sini: biasanya dapat mengirim pesan untuk
nil
membuat kode lebih mudah - Anda tidak perlu memeriksa nilai null di mana pun. Contoh kanonik mungkin adalah metode pengakses:Jika pengiriman pesan ke
nil
tidak valid, metode ini akan menjadi lebih kompleks - Anda harus memiliki dua pemeriksaan tambahan untuk memastikanvalue
dannewValue
tidaknil
sebelum mengirim pesan kepada mereka.Titik terakhir (nilai yang dikembalikan dari pesan ke
nil
juga biasanya valid), meskipun, menambahkan efek pengali ke titik sebelumnya. Sebagai contoh:Kode ini sekali lagi tidak memerlukan pemeriksaan
nil
nilai, dan mengalir secara alami ...Semua ini mengatakan, fleksibilitas tambahan yang dapat mengirim pesan
nil
memang datang dengan biaya tertentu. Ada kemungkinan bahwa pada tahap tertentu Anda akan menulis kode yang gagal dengan cara yang aneh karena Anda tidak memperhitungkan kemungkinan suatu nilainil
.sumber
Dari Greg Parker 's situs :
Jika menjalankan LLVM Compiler 3.0 (Xcode 4.2) atau yang lebih baru
sumber
Ini berarti seringkali tidak perlu memeriksa objek nihil di mana-mana untuk keamanan - terutama:
atau, sebagaimana disebutkan, berbagai metode hitung dan panjang semuanya mengembalikan 0 saat Anda mendapatkan nilai nihil, jadi Anda tidak perlu menambahkan pemeriksaan ekstra untuk nil seluruhnya:
atau ini:
sumber
Jangan berpikir tentang "penerima menjadi nihil"; Saya setuju, bahwa adalah cukup aneh. Jika Anda mengirim pesan ke nihil, tidak ada penerima. Anda hanya mengirim pesan ke nol.
Cara mengatasinya adalah perbedaan filosofis antara Java dan Objective-C: di Java, itu adalah kesalahan; di Objective-C, ini adalah no-op.
sumber
Pesan ObjC yang dikirim ke nihil dan yang nilai kembaliannya memiliki ukuran lebih besar dari sizeof (void *) menghasilkan nilai yang tidak ditentukan pada prosesor PowerPC. Selain itu, pesan ini menyebabkan nilai yang tidak ditentukan dikembalikan di bidang struct yang ukurannya lebih besar dari 8 byte pada prosesor Intel juga. Vincent Gable telah menggambarkan hal ini dengan baik dalam postingan blognya
sumber
Saya rasa tidak ada jawaban lain yang menyebutkan ini dengan jelas: jika Anda terbiasa dengan Java, Anda harus ingat bahwa meskipun Objective-C di Mac OS X memiliki dukungan penanganan pengecualian, ini adalah fitur bahasa opsional yang dapat digunakan. dinyalakan / dimatikan dengan bendera kompilator. Dugaan saya adalah bahwa desain "mengirim pesan ke
nil
aman" ini mendahului dimasukkannya dukungan penanganan pengecualian dalam bahasa dan dilakukan dengan tujuan yang sama: metode dapat kembalinil
untuk menunjukkan kesalahan, dan sejak mengirim pesan kenil
biasanya kembalinil
pada gilirannya, ini memungkinkan indikasi kesalahan menyebar melalui kode Anda sehingga Anda tidak perlu memeriksanya di setiap pesan. Anda hanya perlu memeriksanya pada titik-titik yang penting. Saya pribadi berpikir propagasi & penanganan pengecualian adalah cara yang lebih baik untuk mengatasi tujuan ini, tetapi tidak semua orang setuju dengan itu. (Di sisi lain, saya misalnya tidak menyukai persyaratan Java pada Anda yang harus mendeklarasikan pengecualian apa yang mungkin dilontarkan metode, yang sering kali memaksa Anda untuk menyebarkan deklarasi pengecualian secara sintaksis ke seluruh kode Anda; tetapi itu adalah diskusi lain.)Saya telah memposting jawaban yang serupa, tetapi lebih panjang, untuk pertanyaan terkait "Apakah menegaskan bahwa setiap pembuatan objek berhasil diperlukan di Objective C?" jika Anda ingin lebih detail.
sumber
nil
sering digunakan untuk menghubungkan arus pendek rantai menjadi NO-op.C tidak mewakili apa-apa sebagai 0 untuk nilai primitif, dan NULL untuk pointer (yang setara dengan 0 dalam konteks pointer).
Objective-C dibangun di atas representasi C tentang apa-apa dengan menambahkan nol. nil adalah penunjuk objek ke ketiadaan. Meskipun secara semantik berbeda dari NULL, mereka secara teknis setara satu sama lain.
NSObjects yang baru dialokasikan memulai hidup dengan isinya disetel ke 0. Ini berarti bahwa semua penunjuk yang dimiliki objek ke objek lain dimulai sebagai nil, jadi tidak perlu, misalnya, mengatur self. (Asosiasi) = nil dalam metode init.
Namun, perilaku nil yang paling menonjol adalah bahwa ia dapat mengirim pesan ke sana.
Dalam bahasa lain, seperti C ++ (atau Java), ini akan merusak program Anda, tetapi di Objective-C, memanggil metode pada nil mengembalikan nilai nol. Ini sangat menyederhanakan ekspresi, karena menghilangkan kebutuhan untuk memeriksa nol sebelum melakukan apa pun:
Menyadari cara kerja nil di Objective-C memungkinkan kemudahan ini menjadi fitur, dan bukan bug yang bersembunyi di aplikasi Anda. Pastikan untuk menjaga dari kasus di mana nilai nihil tidak diinginkan, baik dengan memeriksa dan kembali lebih awal untuk gagal secara diam-diam, atau menambahkan NSParameterAssert untuk membuat pengecualian.
Sumber: http://nshipster.com/nil/ https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html (Mengirim Pesan ke nihil).
sumber