NSDefaultRunLoopMode vs NSRunLoopCommonModes

114

Setiap kali saya mencoba mengunduh file besar di belakang UIScrollView, MPMapViewatau sesuatu, proses pengunduhan terhenti segera setelah saya menyentuh layar iPhone. Untungnya, posting blog yang luar biasa dari Jörn menyarankan opsi alternatif, menggunakan NSRunLoopCommonModesuntuk koneksi.

Itu membuat saya melihat secara detail dari dua mode, NSDefaultRunLoopMode dan NSRunLoopCommonModes, tetapi dokumen apel tidak menjelaskan dengan baik, selain mengatakan

NSDefaultRunLoopMode

Mode untuk menangani sumber input selain objek NSConnection. Ini adalah mode run-loop yang paling umum digunakan.

NSRunLoopCommonModes

Objek yang ditambahkan ke run loop menggunakan nilai ini sebagai mode yang dipantau oleh semua mode run loop yang telah dideklarasikan sebagai anggota dari set mode "umum"; lihat deskripsi CFRunLoopAddCommonMode untuk detailnya.

CFRunLoopAddCommonMode

Sumber, pengatur waktu, dan pengamat didaftarkan ke satu atau beberapa mode putaran berjalan dan hanya berjalan ketika putaran putaran berjalan di salah satu mode tersebut. Mode umum adalah sekumpulan mode run loop di mana Anda dapat menentukan sekumpulan sumber, timer, dan pengamat yang digunakan bersama oleh mode ini. Alih-alih mendaftarkan sumber, misalnya, ke setiap mode run loop tertentu, Anda dapat mendaftarkannya satu kali ke mode pseudo umum run loop dan secara otomatis akan terdaftar di setiap mode run loop dalam set mode umum. Demikian juga, ketika mode ditambahkan ke set mode umum, sumber, timer, atau pengamat apa pun yang sudah terdaftar ke mode pseudo umum ditambahkan ke mode umum yang baru ditambahkan.

Adakah yang bisa menjelaskan keduanya dalam bahasa manusia?

Stkim1
sumber

Jawaban:

204

Run loop adalah mekanisme yang memungkinkan sistem membangunkan thread yang tertidur sehingga dapat mengelola peristiwa asinkron. Biasanya ketika Anda menjalankan utas (dengan pengecualian utas utama) ada opsi untuk memulai utas dalam putaran putaran atau tidak. Jika thread menjalankan semacam operasi atau berjalan lama tanpa interaksi dengan peristiwa eksternal dan tanpa timer, Anda tidak memerlukan run loop, tetapi jika thread Anda perlu merespons peristiwa yang masuk, thread harus dilampirkan ke run loop untuk aktifkan utas saat acara baru tiba. Ini adalah kasus NSURLConnectionutas yang dihasilkan, karena mereka hanya bangun pada acara masuk (dari jaringan).

Setiap utas dapat dikaitkan ke beberapa putaran proses, atau dapat dikaitkan ke putaran proses tertentu yang dapat diatur untuk bekerja dalam mode berbeda. "Mode run loop" adalah konvensi yang digunakan oleh OS untuk menetapkan beberapa aturan tentang kapan harus menyampaikan peristiwa tertentu atau mengumpulkannya untuk dikirimkan nanti.

Biasanya semua putaran proses disetel ke "mode default" yang menetapkan cara default untuk mengelola peristiwa masukan. Misalnya: segera setelah peristiwa menyeret mouse (Mac OS) atau menyentuh (di iOS) terjadi maka mode untuk putaran jalan ini disetel ke pelacakan peristiwa; ini berarti bahwa utas tidak akan dibangunkan pada peristiwa jaringan baru tetapi peristiwa ini akan disampaikan nanti ketika peristiwa masukan pengguna berakhir dan putaran proses disetel ke mode default lagi; jelas ini adalah pilihan yang dibuat oleh arsitek OS untuk memprioritaskan acara pengguna daripada acara latar belakang.

Jika Anda memutuskan untuk mengubah mode putaran jalan untuk NSURLConnectionutas Anda , dengan menggunakan scheduleInRunLoop:forModes:, maka Anda dapat menetapkan utas ke mode putaran jalan khusus , daripada putaran putaran default tertentu. Pseudo-mode khusus yang dipanggil NSRunLoopCommonModesdigunakan oleh banyak sumber input termasuk pelacakan peristiwa. Misalnya menetapkan NSURLConnectioninstance ke mode umum berarti mengaitkan kejadiannya ke "mode pelacakan" selain "mode default". Satu keuntungan / kerugian mengaitkan utas dengan NSRunLoopCommonModesutas tidak akan diblokir oleh peristiwa sentuh.

Mode baru dapat ditambahkan ke mode umum, tetapi ini merupakan operasi tingkat rendah.

Saya ingin menutup dengan menambahkan beberapa catatan:

  • Biasanya kita perlu menggunakan sekumpulan gambar atau thumbnail yang diunduh dari jaringan dengan tampilan tabel. Kami mungkin berpikir bahwa mengunduh gambar-gambar ini dari jaringan saat tampilan tabel bergulir dapat meningkatkan pengalaman pengguna (karena kami dapat melihat gambar saat menggulir), tetapi ini tidak menguntungkan karena kelancaran pengguliran dapat sangat terganggu. Dalam contoh ini dengan NSURLConnectionrun loop tidak boleh digunakan; akan lebih baik menggunakan UIScrollViewmetode delegasi untuk mendeteksi ketika pengguliran dihentikan dan kemudian memperbarui tabel dan mengunduh item baru dari jaringan;

  • Anda dapat mempertimbangkan untuk menggunakan GCD yang akan membantu Anda "melindungi" kode Anda dari masalah pengelolaan run loop. Dalam contoh di atas, Anda dapat mempertimbangkan untuk menambahkan permintaan jaringan Anda ke antrian serial kustom.

viggio24
sumber
9
Dear Viggio24, terima kasih banyak atas penjelasan yang bersih dan tepat ini. Saya akan meminta Apple untuk memasukkan komentar Anda ke panduan API mereka. ;)
Stkim1
7
Jawaban viggio24 sempurna. Bagi mereka yang tertarik, saya akan menunjukkan bahwa Sesi 208 (Aplikasi Jaringan untuk iPhone OS, Bagian 2) dari WWDC 2010 berisi intro tentang putaran yang dijalankan. Jika Anda tertarik untuk melihatnya. Semoga membantu.
Lorenzo B
19
Hanya catatan untuk diri saya sendiri: NSRunLoopCommonModesmemungkinkan acara pengatur waktu saat bergulir masuk UIScrollView. NSDefaultRunLoopModecegah timer saat menggulir.
eonil
2
Saya menemukan komentar yang sangat menarik tentang pembaruan tampilan gulir, karena menyebutkan topik yang sangat menantang. Hanya untuk menambahkan detail lebih lanjut tentang ini: Saat Anda menyetel mode untuk NSURLConnection, ini hanya memengaruhi eksekusi panggilan balik delegasi. Saya memahami bahwa memperbarui scrollView di sini dapat menyebabkan masalah kinerja, tetapi mengapa ini terjadi? Jika jawabannya adalah gambar harus dimuat ke dalam memori, Anda dapat melakukannya dengan menulis ke dalam konteks grafik di latar belakang, dan memperbarui lapisan utas tampilan Anda setelah melakukan ini. apakah ini terdengar masuk akal?
nebillo