Apa gunanya NSAssert, sebenarnya?

155

Saya harus menanyakan ini, karena: Satu-satunya hal yang saya kenali adalah, bahwa jika pernyataan gagal, aplikasi mogok. Apakah itu alasan mengapa menggunakan NSAssert? Atau apa lagi manfaatnya? Dan apakah benar untuk meletakkan NSAssert tepat di atas asumsi yang saya buat dalam kode, seperti fungsi yang seharusnya tidak pernah menerima -1 sebagai param tetapi mungkin -0.9 atau -1.1?

TheNeil
sumber

Jawaban:

300

Menegaskan adalah memastikan nilai adalah apa yang seharusnya. Jika pernyataan gagal berarti ada yang tidak beres dan aplikasi berhenti. Salah satu alasan untuk menggunakan menegaskan adalah jika Anda memiliki beberapa fungsi yang tidak akan berperilaku atau akan menciptakan efek samping yang sangat buruk jika salah satu parameter yang diteruskan ke itu bukan beberapa nilai (atau kisaran nilai), Anda dapat membuat pernyataan untuk membuat yakin bahwa nilai adalah apa yang Anda harapkan, dan jika tidak maka ada sesuatu yang salah, dan aplikasi berhenti. Penegasan dapat sangat berguna untuk debugging / pengujian unit, dan juga ketika Anda memberikan kerangka kerja untuk menghentikan pengguna melakukan hal-hal "jahat".

Daniel
sumber
9
Anda harus mengeluarkan NSAssert untuk rilis. Ada bendera waktu kompilasi untuk melakukan itu.
Barry Wark
127
> Anda harus mengeluarkan NSAssert untuk rilis. Ini bisa diperdebatkan. Saya selalu merilis aplikasi saya dengan pernyataan diaktifkan, dan ini adalah praktik standar untuk banyak perangkat lunak, Apple misalnya melakukan ini. Segera setelah program Anda mendeteksi keadaan abnormal, Anda akan mengalami crash. Anda bisa mendapatkan jejak jejak di mana kesalahan terjadi, sedangkan jika Anda menonaktifkan menegaskan Anda bisa berakhir merusak memori dan / atau data pengguna dan masalahnya akan sangat sulit untuk di-debug.
Mike Weller
18
Perhatikan bahwa XCode 4 memiliki NS_BLOCK_ASSERTIONS yang ditentukan secara default dalam konfigurasi rilis. Saya kira jika Anda tidak mengubah kode yang dirilis tidak akan mengandung NSAssert: s.
Jonny
16
Jika saya mengerti dengan benar, apa gunanya meninggalkan mereka (pada versi rilis)? Mengapa tidak mengganti NSAssert dengan pernyataan if, dan if (sesuatu yang mengerikan terjadi), kemudian beri tahu pengguna (atau lakukan sesuatu yang berada di bawah kendali Anda ), dan jangan hanya berhenti / crash dan biarkan pengguna bertanya-tanya apa yang terjadi ... Atau apakah saya melewatkan sesuatu?
Gik
11
Ini adalah buang-buang waktu pengembang untuk menyusuri jalan setiap kasus luar biasa yang tidak seharusnya terjadi sama sekali dalam keadaan normal. Ini melibatkan memikirkan cara yang tepat untuk memberi tahu pengguna untuk masing-masing dari mereka dan / atau membuat aplikasi cukup kuat untuk dijalankan dengan cara yang diharapkan setelah terjadinya. Pendekatan yang lebih praktis adalah menghentikan aplikasi dan memperbaiki bug yang ditemukan dari laporan kerusakan dan merilis versi baru. Karena itu, penting untuk memastikan bahwa tidak ada kehilangan data dalam situasi seperti itu. Namun ini harus dipastikan tetapi ini jauh lebih sedikit pekerjaannya.
trss
20

Saya tidak dapat benar-benar berbicara dengan NSAssert, tetapi saya membayangkan bahwa ia bekerja mirip dengan pernyataan C ().

assert () digunakan untuk menegakkan kontrak semantik dalam kode Anda. Apa artinya itu, Anda bertanya?

Yah, seperti yang Anda katakan: jika Anda memiliki fungsi yang seharusnya tidak pernah menerima -1, Anda dapat menegaskan () menegakkan bahwa:

membatalkan gimme_positive_ints (int i) {
  menegaskan (i> 0);
}

Dan sekarang Anda akan melihat sesuatu seperti ini di log kesalahan (atau STDERR):

Pernyataan i> 0 gagal: file example.c, baris 2

Jadi tidak hanya itu melindungi dari input yang berpotensi buruk tetapi juga mencatatnya dengan cara yang bermanfaat dan standar.

Oh, dan setidaknya dalam C menegaskan () adalah makro, sehingga Anda bisa mendefinisikan kembali menegaskan () sebagai no-op dalam kode rilis Anda. Saya tidak tahu apakah itu masalahnya dengan NSAssert (atau bahkan menegaskan () lagi, tapi itu cukup berguna untuk menyusun cek itu.

Mando Escamilla
sumber
2
Ya, NSAssert juga makro.
Martin Wickman
18

NSAssertmemberi Anda lebih dari sekadar menabrak aplikasi. Ini memberi tahu Anda kelas, metode, dan garis di mana pernyataan itu terjadi. Semua pernyataan juga dapat dengan mudah dinonaktifkan menggunakan NS_BLOCK_ASSERTIONS. Sehingga membuatnya lebih cocok untuk debugging. Di sisi lain, melempar NSExceptionhanya akan merusak aplikasi. Ini juga tidak memberi tahu tentang lokasi pengecualian, juga tidak dapat dinonaktifkan begitu saja. Lihat perbedaan pada gambar di bawah ini.

Aplikasi mogok karena pernyataan juga memunculkan pengecualian, seperti yang dinyatakan oleh dokumentasi NSAssert :

Saat dipanggil, penangan pernyataan mencetak pesan kesalahan yang mencakup metode dan nama kelas (atau nama fungsi). Itu kemudian memunculkan eksepsi NSInternalInconsistencyException.

NSAssert:

Log setelah pernyataan

NSException:

Log setelah pengecualian

Abdurrahman Mubeen Ali
sumber
Sebuah NSExceptionmemberikan banyak peluang untuk menyesuaikan output yang dihasilkannya melalui reasondan userInfoparameter. Tidak ada alasan Anda tidak dapat menambahkan nama kelas, pemilih, informasi baris, dan hal lain yang ingin Anda tambahkan untuk membantu debugging. IMHO, Anda menggunakan NSAssertuntuk tujuan debugging selama pengembangan tetapi menonaktifkannya untuk mengirim; Anda melempar NSExceptionjika Anda ingin memberikan pernyataan dalam kode pengiriman.
markeissler
17

Terlepas dari apa yang semua orang katakan di atas, perilaku default NSAssert()(tidak seperti C assert()) adalah untuk melemparkan pengecualian, yang dapat Anda tangkap dan tangani. Misalnya, Xcode melakukan ini.

Jens Ayton
sumber
Apakah ada lebih banyak tentang bagaimana kita dapat menangkap dan menangani pengecualian?
Gon
1
Pengecualian dalam kakao BUKAN "dapat ditangkap dan ditangani" secara de facto. Jika kontrol melewati fungsi apel sama sekali di mana saja di pohon panggilan, perilaku tidak ditentukan. Pengecualian adalah murni untuk pelaporan kesalahan (alias, crittercism, dll), bukan untuk penggunaan umum seperti di Jawa.
Michael
9

Hanya untuk mengklarifikasi, seperti yang disebutkan seseorang tetapi tidak sepenuhnya dijelaskan, alasan untuk memiliki dan menggunakan pernyataan alih-alih hanya membuat kode kustom (melakukan jika dan menaikkan pengecualian untuk data yang buruk, misalnya) adalah bahwa menegaskan HARUS dinonaktifkan untuk aplikasi produksi.

Saat mengembangkan dan debugging, menegaskan diaktifkan bagi Anda untuk menangkap kesalahan. Program akan berhenti ketika pernyataan dievaluasi sebagai false. Tetapi, ketika mengkompilasi untuk produksi, kompiler menghilangkan kode pernyataan dan benar-benar membuat program Anda berjalan lebih cepat. Saat itu, semoga, Anda telah memperbaiki semua bug. Jika program Anda masih memiliki bug saat dalam produksi (ketika pernyataan dinonaktifkan dan program "melompati" pernyataan), program Anda mungkin akan berakhir mogok di beberapa titik lain.

Dari bantuan NSAssert: "Pernyataan dinonaktifkan jika makro NS_BLOCK_ASSERTIONS preprocessor ditentukan." Jadi, cukup letakkan makro di target distribusi Anda [saja].

Ohad Kravchick
sumber
6

NSAssert(dan setara dengan stdlib assert) adalah untuk mendeteksi kesalahan pemrograman selama pengembangan. Anda seharusnya tidak pernah memiliki pernyataan yang gagal dalam aplikasi produksi (dirilis). Jadi, Anda mungkin menegaskan bahwa Anda tidak pernah memberikan angka negatif ke metode yang membutuhkan argumen positif. Jika pernyataan pernah gagal selama pengujian, Anda memiliki bug. Namun, jika nilai yang diteruskan dimasukkan oleh pengguna, Anda perlu melakukan validasi input yang benar daripada mengandalkan pernyataan dalam produksi (Anda dapat menetapkan #define untuk rilis build yang menonaktifkan NSAssert*.

Barry Wark
sumber
2
+1 karena jawaban Anda paling masuk akal bagi saya! Menggunakan NSAssert lebih masuk akal jika digunakan untuk pengembangan, bukan setelah rilis. Seorang pengguna memasukkan nilai yang tidak diizinkan harus diikuti oleh kesalahan UI, bukan NSAssert menabrak aplikasi. Kabut telah hilang!
pnizzle
3

Penegasan biasanya digunakan untuk menegakkan penggunaan metode tertentu atau logika tertentu. Katakanlah Anda sedang menulis metode yang menghitung jumlah dua bilangan bulat lebih besar dari nol. Untuk memastikan metode ini selalu digunakan sebagaimana dimaksud, Anda mungkin akan memberikan pernyataan yang menguji kondisi tersebut.

Jawaban singkat: Mereka menegaskan bahwa kode Anda hanya digunakan sebagaimana dimaksud.

Lounge
sumber
3

Ini bermanfaat untuk menunjukkan bahwa selain menjalankan memeriksa waktu, menegaskan pemrograman adalah fasilitas penting yang digunakan ketika Anda merancang kode Anda dengan kontrak.

Info lebih lanjut tentang masalah penegasan dan desain berdasarkan kontrak dapat ditemukan di bawah:

Pernyataan (pengembangan perangkat lunak)

Desain berdasarkan kontrak

Pemrograman Dengan Pernyataan

Desain dengan Kontrak, dengan Contoh [Paperback]

Anugerah
sumber
2

Untuk sepenuhnya menjawab pertanyaannya, poin dari segala jenis pernyataan adalah untuk membantu debugging. Lebih baik menangkap kesalahan pada sumbernya, kemudian menangkapnya di debugger saat menyebabkan crash.

Misalnya, Anda dapat meneruskan nilai ke fungsi yang mengharapkan nilai dalam rentang tertentu. Fungsi dapat menyimpan nilai untuk digunakan nanti, dan nanti menggunakan aplikasi crash. Tumpukan panggilan yang terlihat dalam skenario ini tidak akan menunjukkan sumber nilai buruk. Lebih baik untuk menangkap nilai buruk ketika datang untuk mencari tahu siapa yang melewati nilai buruk dan mengapa.

Robert Hawkey
sumber
-3

NSAssertmembuat aplikasi mogok saat itu sesuai dengan kondisi. Jika tidak cocok dengan kondisi, pernyataan selanjutnya akan dieksekusi. Cari EX di bawah ini:

Saya hanya membuat aplikasi untuk menguji apa tugasnya NSAssertadalah:

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self testingFunction:2];
}

-(void)testingFunction: (int)anNum{
    // if anNum < 2 -> the app will crash
    // and the NSLog statement will not execute
    // that mean you cannot see the string: "This statement will execute when anNum < 2"
    // into the log console window of Xcode
    NSAssert(anNum >= 2, @"number you enter less than 2");
    // If anNum >= 2 -> the app will not crash and the below 
    // statement will execute
    NSLog(@"This statement will execute when anNum < 2");
}

ke dalam kode saya aplikasi tidak akan crash. Dan test case adalah:

  • anNum > = 2 -> Aplikasi tidak akan crash dan Anda dapat melihat string log: "Pernyataan ini akan dieksekusi ketika angka <2" ke dalam jendela konsol log outPut
  • anNum <2 -> Aplikasi akan macet dan Anda tidak dapat melihat log string: "Pernyataan ini akan dieksekusi ketika suatuNum <2"

sumber
1
Anda mendapatkannya sebaliknya. "NSAssert membuat aplikasi macet ketika cocok dengan kondisi. Jika tidak cocok dengan kondisi, pernyataan selanjutnya akan dieksekusi". NSAssert crash aplikasi jika TIDAK cocok dengan kondisi, dan jalankan secara normal jika TIDAK cocok dengan kondisi.
Joe Tam
Aplikasi macet dan catat pesan ketika tidak memenuhi kondisi sebaliknya dieksekusi lebih lanjut.
Pravin S.