Selain perbedaan yang jelas:
- Menggunakan
enumerateObjectsUsingBlock
saat Anda membutuhkan indeks dan objek Jangan gunakan(saya salah tentang ini, lihat jawaban bbum)enumerateObjectsUsingBlock
ketika Anda perlu memodifikasi variabel lokal
Apakah enumerateObjectsUsingBlock
umumnya dianggap lebih baik atau lebih buruk ketika for (id obj in myArray)
juga akan bekerja? Apa kelebihan / kekurangannya (misalnya performanya kurang lebih)?
objective-c
multithreading
ios4
objective-c-blocks
Paul Wheeler
sumber
sumber
Jawaban:
Pada akhirnya, gunakan pola apa pun yang ingin Anda gunakan dan datang lebih alami dalam konteks.
Meskipun
for(... in ...)
cukup nyaman dan singkat secara sintaksis,enumerateObjectsUsingBlock:
memiliki sejumlah fitur yang mungkin atau mungkin tidak terbukti menarik:enumerateObjectsUsingBlock:
akan lebih cepat atau lebih cepat daripada pencacahan cepat (for(... in ...)
menggunakanNSFastEnumeration
dukungan untuk mengimplementasikan pencacahan). Penghitungan cepat memerlukan terjemahan dari representasi internal ke representasi untuk penghitungan cepat. Ada overhead di dalamnya. Enumerasi berbasis blok memungkinkan kelas koleksi untuk menghitung konten secepat traversal tercepat dari format penyimpanan asli. Agak tidak relevan untuk array, tetapi bisa menjadi perbedaan besar untuk kamus."Jangan gunakan enumerateObjectsUsingBlock ketika Anda perlu memodifikasi variabel lokal" - tidak benar; Anda dapat mendeklarasikan penduduk lokal Anda sebagai
__block
dan mereka akan dapat ditulis di blok.enumerateObjectsWithOptions:usingBlock:
mendukung enumerasi bersamaan atau terbalik.dengan kamus, enumerasi berbasis blok adalah satu-satunya cara untuk mengambil kunci dan nilai secara bersamaan.
Secara pribadi, saya menggunakan
enumerateObjectsUsingBlock:
lebih sering daripadafor (... in ...)
, tetapi - lagi - pilihan pribadi.sumber
enumerateObjectsUsingBlock
masih jauh lebih lambat daripada penghitungan cepat untuk array dan set. Kenapa ya? iosdevelopertips.com/objective-c/…enumerateObjectsUsingBlock
membungkus setiap doa blok dengan kumpulan autorelease (setidaknya pada OS X 10.10). Ini menjelaskan perbedaan kinerja dibandingkanfor in
yang tidak melakukan itu.Untuk enumerasi sederhana, cukup menggunakan enumerasi cepat (yaitu
for…in…
loop) adalah opsi yang lebih idiomatis. Metode blok mungkin sedikit lebih cepat, tetapi itu tidak terlalu penting dalam banyak kasus - beberapa program terikat dengan CPU, dan meskipun itu jarang bahwa loop itu sendiri daripada perhitungan di dalamnya akan menjadi hambatan.Simpul sederhana juga membaca lebih jelas. Inilah pelat dari kedua versi:
Bahkan jika Anda menambahkan variabel untuk melacak indeks, loop sederhana lebih mudah dibaca.
Jadi kapan sebaiknya Anda gunakan
enumerateObjectsUsingBlock:
? Saat Anda menyimpan blok untuk dieksekusi nanti atau di banyak tempat. Ini bagus untuk saat Anda benar-benar menggunakan blok sebagai fungsi kelas satu daripada pengganti yang terlalu padat untuk bodi loop.sumber
enumerateObjectsUsingBlock:
akan memiliki kecepatan yang sama atau lebih cepat dari penghitungan cepat dalam semua kasus.for(... in ...)
menggunakan penghitungan cepat yang membutuhkan pengumpulan untuk menyediakan beberapa representasi sementara dari struktur data internal. Seperti yang Anda perhatikan, kemungkinan tidak relevan.When you're storing a block to execute later or in multiple places. It's good for when you're actually using a block as a first-class function rather than an overwrought replacement for a loop body.
enumerateObjects...
sebenarnya bisa lebih lambat daripada penghitungan cepat dengan satu lingkaran. Saya menjalankan tes ini beberapa ribu kali; tubuh blok dan loop adalah baris kode yang sama:[(NSOperation *)obj cancel];
. Rata-rata: loop cepat enum --[JHStatusBar dequeueStatusMessage:] [Line: 147] Fast enumeration time (for..in..loop): 0.000009
dan untuk blok --[JHStatusBar dequeueStatusMessage:] [Line: 147] Enumeration time using block: 0.000043
. Aneh bahwa perbedaan waktu begitu besar dan konsisten tetapi, jelas, ini adalah kasus uji yang sangat spesifik.Meskipun pertanyaan ini sudah tua, banyak hal belum berubah, jawaban yang diterima salah.
The
enumerateObjectsUsingBlock
API tidak dimaksudkan untuk menggantikanfor-in
, tapi untuk kasus penggunaan yang sama sekali berbeda:withOptions:
parameter)Enumerasi cepat dengan
for-in
masih idiomatik metode untuk menghitung koleksi.Penghitungan Cepat mendapat manfaat dari singkatnya kode, keterbacaan, dan optimisasi tambahan yang membuatnya cepat secara tidak wajar. Lebih cepat dari pada C-loop lama!
Tes cepat menyimpulkan bahwa pada tahun 2014 di iOS 7,
enumerateObjectsUsingBlock
secara konsisten lebih lambat 700% dari pada untuk-in (berdasarkan iterasi 1mm dari array 100 item).Apakah kinerja merupakan masalah praktis yang nyata di sini?
Jelas tidak, dengan pengecualian langka.
Intinya adalah untuk menunjukkan bahwa ada sedikit keuntungan untuk menggunakan
enumerateObjectsUsingBlock:
lebihfor-in
tanpa alasan yang benar-benar baik. Itu tidak membuat kode lebih mudah dibaca ... atau lebih cepat ... atau aman utas. (Kesalahpahaman umum lainnya).Pilihannya adalah preferensi pribadi. Bagi saya, opsi idiomatis dan mudah dibaca menang. Dalam hal ini, yaitu Penghitungan Cepat menggunakan
for-in
.Benchmark:
Hasil:
sumber
enumerateObjectsUsingBlock
sebenarnya 5X lebih lambat. Itu tampaknya karena kolam autorelease yang membungkus setiap doa blok, yang tidak terjadi untukfor in
kasus ini.enumerateObjectsUsingBlock:
masih 4X lebih lambat pada iPhone 6 iOS9 nyata, menggunakan Xcode 7.x untuk membangun.enumerate
sintaksis karena rasanya seperti FP dan tidak ingin mendengarkan analisis kinerja.enumerate:
Untuk menjawab pertanyaan tentang kinerja, saya melakukan beberapa tes menggunakan proyek tes kinerja saya . Saya ingin tahu yang mana dari tiga opsi untuk mengirim pesan ke semua objek dalam array yang tercepat.
Pilihannya adalah:
1) makeObjectsPerformSelector
2) penghitungan cepat & pengiriman pesan reguler
3) enumerateObjectsUsingBlock & kirim pesan biasa
Ternyata makeObjectsPerformSelector adalah yang paling lambat sejauh ini. Butuh pencacahan dua kali lebih lama. Dan enumerateObjectsUsingBlock adalah yang tercepat, itu sekitar 15-20% lebih cepat dari iterasi cepat.
Jadi, jika Anda sangat khawatir tentang kinerja terbaik, gunakan enumerateObjectsUsingBlock. Tetapi perlu diingat bahwa dalam beberapa kasus waktu yang diperlukan untuk menghitung koleksi dikerdilkan oleh waktu yang diperlukan untuk menjalankan kode apa pun yang Anda ingin setiap objek dieksekusi.
sumber
Ini cukup berguna untuk menggunakan enumerateObjectsUsingBlock sebagai loop luar ketika Anda ingin memecah loop bersarang.
misalnya
Alternatifnya adalah menggunakan pernyataan goto.
sumber
Terima kasih kepada @bbum dan @Chuck untuk memulai perbandingan komprehensif tentang kinerja. Senang mengetahui ini sepele. Saya sepertinya telah mengikuti:
for (... in ...)
- sebagai goto default saya. Lebih intuitif bagi saya, lebih banyak sejarah pemrograman di sini daripada preferensi sebenarnya - penggunaan kembali lintas bahasa, kurang mengetik untuk sebagian besar struktur data karena IDE otomatis lengkap: P.enumerateObject...
- ketika akses ke objek dan indeks diperlukan. Dan ketika mengakses struktur non-array atau kamus (preferensi pribadi)for (int i=idx; i<count; i++)
- untuk array, ketika saya harus mulai dengan indeks yang tidak nolsumber