untuk drawRect atau tidak drawRect (kapan seseorang harus menggunakan drawRect/Core Graphics vs subviews/gambar dan kenapa?)

Untuk memperjelas tujuan dari pertanyaan ini: saya tahu CARA membuat rumit pandangan dengan kedua subviews dan menggunakan drawRect. I'm mencoba untuk memahami ketika's dan mengapa's untuk menggunakan salah satu dari yang lain. Saya juga memahami bahwa itu doesn't masuk akal untuk mengoptimalkan bahwa banyak dari waktu ke depan, dan melakukan sesuatu yang lebih sulit cara sebelum melakukan profiling. Mempertimbangkan bahwa saya'm nyaman dengan kedua metode, dan sekarang benar-benar ingin pemahaman yang lebih dalam. Banyak kebingungan saya datang dari belajar bagaimana untuk membuat tampilan tabel gulir kinerja benar-benar halus dan cepat. Tentu saja sumber aslinya dari metode ini adalah dari penulis di balik twitter untuk iPhone (sebelumnya tweetie). Pada dasarnya, dikatakan bahwa untuk membuat tabel bergulir mentega halus, rahasianya adalah untuk TIDAK menggunakan subviews, tapi bukannya melakukan semua gambar dalam satu custom uiview. Pada dasarnya tampaknya menggunakan banyak subviews memperlambat render down karena mereka memiliki banyak overhead, dan terus-menerus kembali composited atas pandangan orang tua mereka. Untuk menjadi adil, ini ditulis ketika 3GS cukup merek spankin baru, dan iDevices telah mendapat jauh lebih cepat sejak saat itu. Masih metode rutin disarankan pada interwebs dan di tempat lain untuk kinerja tinggi tabel. Sebenarnya itu's sebuah metode yang disarankan dalam Apple's Tabel Sampel Kode, telah disarankan dalam beberapa video WWDC (Praktis Menggambar untuk Pengembang iOS), dan banyak iOS buku pemrograman. Bahkan ada awesome mencari tools untuk desain grafis dan menghasilkan Inti Grafis kode untuk mereka. Jadi pada awalnya saya'm mengarah untuk percaya "ada alasan mengapa Inti Grafis yang ada. Ini CEPAT!" Tapi begitu saya pikir saya mendapatkan ide "Mendukung Core Graphics bila mungkin", saya mulai melihat bahwa drawRect sering bertanggung jawab untuk miskin tanggap dalam aplikasi, adalah sangat mahal memori bijaksana, dan benar-benar pajak CPU. Pada dasarnya, bahwa saya harus "Hindari utama drawRect" (WWDC 2012 iOS App Kinerja: Grafis dan Animasi) Jadi saya kira, seperti segala sesuatu, it's rumit. Mungkin anda bisa membantu diri sendiri dan orang lain memahami Ketika's dan Mengapa's untuk menggunakan drawRect? Saya melihat beberapa situasi yang jelas untuk menggunakan Core Grafis:

  1. Anda memiliki data dinamis (Apple's Saham Grafik contoh)
  2. Anda memiliki fleksibel elemen UI yang dapat't dapat dilaksanakan dengan sederhana resizable gambar
  3. Anda membuat grafis yang dinamis, yang pernah diberikan digunakan di beberapa tempat Saya melihat situasi untuk menghindari Core Grafis:
  4. Sifat dari pandangan anda butuhkan untuk animasi secara terpisah
  5. Anda memiliki relatif kecil melihat hirarki, sehingga apapun yang dirasakan usaha ekstra dengan menggunakan CG isn't layak mendapatkan
  6. Anda ingin memperbarui potongan pandangan tanpa menggambar ulang seluruh hal
  7. Tata letak anda subviews kebutuhan untuk memperbarui ketika orang tua melihat perubahan ukuran Memberikan pengetahuan anda. Dalam situasi apa yang anda mencapai untuk drawRect/Core Grafis (yang juga bisa dicapai dengan subviews)? Faktor-faktor apa yang menyebabkan anda mengambil keputusan itu? Bagaimana/Mengapa menggambar dalam satu tampilan kustom dianjurkan untuk mentega halus sel tabel bergulir, namun Apple menyarankan drawRect melawan untuk alasan kinerja secara umum? Bagaimana dengan gambar latar belakang yang sederhana (ketika anda menciptakan mereka dengan CG vs menggunakan resizable gambar png)? Pemahaman yang mendalam tentang subjek ini mungkin tidak diperlukan untuk membuat berharga apps, tapi aku don't cinta memilih antara teknik tanpa mampu menjelaskan mengapa. Otak saya marah pada saya.

    Pertanyaan Update ##

    Terima kasih untuk informasi semua orang. Beberapa mengklarifikasi pertanyaan-pertanyaan berikut ini:

  8. Jika anda menggambar sesuatu dengan core grafis, tetapi dapat mencapai hal yang sama dengan UIImageViews dan pra-diberikan png, anda harus selalu pergi rute itu?
  9. Pertanyaan serupa: Terutama dengan badass alat-alat seperti ini, ketika anda harus mempertimbangkan menggambar elemen antarmuka inti grafis? (Mungkin ketika tampilan elemen anda adalah variabel. misalnya tombol dengan 20 variasi warna yang berbeda. Kasus lain?)
  10. Diberikan pemahaman saya dalam jawaban saya di bawah ini, bisa sama keuntungan kinerja untuk sel tabel mungkin bisa diperoleh dengan efektif menangkap snapshot bitmap dari ponsel anda setelah anda kompleks UIView membuat's itu sendiri, dan menampilkan yang sementara bergulir dan bersembunyi di kompleks anda lihat? Jelas beberapa potongan akan harus bekerja keluar. Hanya sebuah pemikiran yang menarik yang saya punya.
Larutan

Tongkat untuk UIKit dan subviews setiap kali anda bisa. Anda dapat menjadi lebih produktif, dan mengambil keuntungan dari semua OO mekanisme yang harus hal-hal yang lebih mudah untuk mempertahankan. Menggunakan Core Grafis ketika anda dapat't mendapatkan kinerja yang anda butuhkan dari UIKit, atau anda tahu mencoba untuk hack bersama-sama efek gambar di UIKit akan menjadi lebih rumit.

Secara umum alur kerja harus membangun tableviews dengan subviews. Menggunakan Instrumen untuk mengukur frame rate pada tertua hardware aplikasi anda akan mendukung. Jika anda dapat't mendapatkan 60fps, drop-down untuk CoreGraphics. Bila anda've melakukan ini untuk sementara waktu, anda mendapatkan rasa untuk saat UIKit mungkin membuang-buang waktu.

Jadi, mengapa Inti Grafis yang cepat?

CoreGraphics isn't benar-benar cepat. Jika itu's digunakan sepanjang waktu, anda're mungkin akan lambat. It's kaya gambar API, yang membutuhkan kerja sama dilakukan pada CPU, sebagai lawan banyak UIKit kerja yang diturunkan ke GPU. Jika anda telah menghidupkan sebuah bola bergerak di layar, itu akan menjadi ide yang buruk untuk memanggil setNeedsDisplay pada pandangan 60 kali per detik. Jadi, jika anda memiliki sub-komponen dari pandangan anda yang perlu individual animasi, masing-masing komponen harus menjadi lapisan yang terpisah.

Masalah lain adalah bahwa ketika anda don't melakukan custom menggambar dengan drawRect, UIKit dapat mengoptimalkan saham pandangan jadi drawRect adalah no-op, atau dapat mengambil jalan pintas dengan compositing. Ketika anda mengganti drawRect, UIKit harus mengambil jalur lambat karena tidak memiliki gagasan apa yang anda're lakukan.

Dua masalah ini dapat sebanding dengan manfaat dalam kasus table view cells. Setelah drawRect disebut ketika melihat pertama kali muncul pada layar, isi cache, dan bergulir adalah terjemahan sederhana yang dilakukan oleh GPU. Karena anda're berurusan dengan satu pandangan, daripada hirarki kompleks, UIKit's drawRect optimasi menjadi kurang penting. Sehingga kemacetan menjadi berapa banyak anda dapat mengoptimalkan Core Grafis yang menggambar.

Setiap kali anda bisa, menggunakan UIKit. Melakukan implementasi sederhana yang bekerja. Profil. Ketika ada's insentif, mengoptimalkan.

Komentar (0)

Perbedaannya adalah bahwa UIView dan CALayer pada dasarnya bergerak di bidang fixed gambar. Gambar-gambar ini di-upload ke kartu grafis (jika anda tahu OpenGL, pikirkan sebuah gambar sebagai tekstur, dan UIView/CALayer sebagai poligon yang menunjukkan tekstur seperti itu). Setelah gambar di GPU, hal ini dapat diambil dengan sangat cepat, dan bahkan beberapa kali, dan (dengan sedikit kinerja hukuman) bahkan dengan berbagai tingkat transparansi alpha di atas gambar lain.

CoreGraphics/Kuarsa adalah API untuk menghasilkan gambar. Dibutuhkan pixel penyangga (sekali lagi, berpikir OpenGL tekstur) dan perubahan individu piksel di dalamnya. Ini semua terjadi dalam RAM dan CPU, dan hanya sekali Kuarsa dilakukan, gambar tidak mendapatkan "memerah" kembali ke GPU. Ini round-trip untuk mendapatkan gambar dari GPU, berubah, kemudian meng-upload seluruh gambar (atau setidaknya yang relatif besar potongan itu) kembali ke GPU agak lambat. Juga, sebenarnya gambar yang Kuarsa, sedangkan yang benar-benar cepat untuk apa yang anda lakukan, adalah cara yang lebih lambat dari apa GPU tidak.

Yang's jelas, mempertimbangkan GPU yang sebagian besar bergerak di sekitar tidak berubah piksel dalam potongan besar. Kuarsa tidak acak-akses piksel dan saham CPU dengan jaringan, audio dll. Juga, jika anda memiliki beberapa elemen yang anda menggambar menggunakan Kuarsa pada saat yang sama, anda harus menggambar ulang semua dari mereka ketika salah satu perubahan, kemudian meng-upload seluruh chunk, sementara jika anda mengubah salah satu gambar dan kemudian membiarkan UIViews atau CALayers paste ke gambar lain, anda bisa lolos dengan meng-upload jumlah yang lebih kecil dari data ke GPU.

Ketika anda don't melaksanakan -drawRect:, kebanyakan pandangan yang hanya dapat dioptimalkan jauh. Mereka don't berisi piksel, sehingga dapat't menggambar apa-apa. Pandangan lain, seperti UIImageView, hanya menggambar UIImage (yang, sekali lagi, pada dasarnya adalah sebuah referensi untuk sebuah tekstur, yang mungkin sudah pernah dimuat ke GPU). Jadi jika anda menggambar yang sama UIImage 5 kali menggunakan UIImageView, hanya upload ke GPU sekali, dan kemudian ditarik ke tampilan di 5 lokasi yang berbeda, menghemat waktu kita dan CPU.

Ketika anda menerapkan -drawRect:, hal ini menyebabkan gambar baru yang akan dibuat. Anda kemudian menarik ke pada CPU menggunakan Kuarsa. Jika anda menggambar UIImage di drawRect, kemungkinan men-download gambar dari GPU, salinan itu ke dalam gambar anda're menggambar, dan setelah anda're selesai, upload ini salinan kedua gambar kembali ke kartu grafis. Jadi anda're menggunakan dua GPU memori pada perangkat.

Jadi cara tercepat untuk menarik biasanya untuk menjaga konten statis dipisahkan dari mengubah konten (terpisah UIViews/UIView subclass/CALayers). Beban statis konten sebagai UIImage dan menarik ini menggunakan UIImageView dan menempatkan konten yang dihasilkan secara dinamis pada saat runtime dalam drawRect. Jika anda memiliki konten yang akan ditarik berulang kali, tetapi dengan sendirinya tidak't perubahan (I. e. 3 ikon yang ditampilkan di slot yang sama untuk menunjukkan beberapa status) menggunakan UIImageView juga.

Satu peringatan: Ada hal seperti terlalu banyak UIViews. Terutama daerah yang transparan mengambil tol lebih besar pada GPU untuk menggambar, karena mereka harus dicampur dengan piksel di belakang mereka ketika ditampilkan. Inilah sebabnya mengapa anda dapat menandai UIView sebagai "buram", untuk menunjukkan ke GPU bahwa hal itu hanya dapat melenyapkan segala sesuatu di balik gambar itu.

Jika anda memiliki konten yang dihasilkan secara dinamis pada saat runtime tetapi tetap sama selama aplikasi's seumur hidup (misalnya, sebuah label yang berisi nama pengguna) itu mungkin benar-benar masuk akal untuk hanya menarik semuanya setelah menggunakan Kuarsa, dengan teks, tombol perbatasan dll., sebagai bagian dari latar belakang. Tapi yang's biasanya optimasi yang's tidak diperlukan kecuali Instrumen app memberitahu anda berbeda.

Komentar (6)

Aku'm akan mencoba dan membuat ringkasan dari apa yang saya'm ekstrapolasi dari yang lain's jawaban di sini, dan meminta klarifikasi pertanyaan di update ke pertanyaan awal. Tapi saya mendorong orang lain untuk menjaga jawaban datang dan memilih orang-orang yang telah memberikan informasi yang baik.

Pendekatan

It's cukup jelas bahwa pendekatan umum, seperti Ben Sandofsky disebutkan dalam jawaban, harus "Setiap kali anda bisa, menggunakan UIKit. Melakukan implementasi sederhana yang bekerja. Profil. Ketika ada's insentif, mengoptimalkan."

Mengapa

  1. Ada dua utama kemacetan yang mungkin di iDevice, CPU dan GPU
  2. CPU adalah bertanggung jawab untuk awal drawing/rendering view
  3. GPU yang bertanggung jawab untuk sebagian besar animasi (Inti Animasi), layer efek, compositing, dll.
  4. UIView memiliki banyak optimasi, cache, dll, yang dibangun untuk menangani kompleks lihat hierarki
  5. Ketika meng-override drawRect anda lewatkan banyak manfaat UIView's menyediakan, dan itu's umumnya lebih lambat daripada membiarkan UIView menangani rendering.

Menggambar sel-sel isi di salah satu televisi UIView dapat sangat meningkatkan FPS pada bergulir tabel.

Seperti yang saya katakan di atas, CPU dan GPU dua kemungkinan kemacetan. Karena mereka umumnya menangani hal-hal yang berbeda, anda harus membayar perhatian yang bottleneck anda menjalankan melawan. Dalam kasus bergulir tabel, it's tidak bahwa Inti Grafis adalah gambar yang lebih cepat, dan yang's mengapa hal ini dapat sangat meningkatkan FPS.

Pada kenyataannya, Inti Grafis yang sangat baik mungkin lebih lambat dari yang bersarang UIView hirarki untuk awal render. Namun, tampaknya khas alasan berombak bergulir anda bottlenecking GPU, sehingga anda perlu untuk mengatasi itu.

Kenapa utama drawRect (menggunakan core graphics) dapat membantu meja bergulir:

Dari apa yang saya mengerti, GPU tidak bertanggung jawab awal render dari pandangan, tapi malah menyerahkan tekstur, atau bitmap, kadang-kadang dengan beberapa layer properties, setelah mereka telah diberikan. Hal ini kemudian bertanggung jawab untuk compositing bitmaps, render semua lapisan mempengaruhi, dan mayoritas dari animasi (Inti Animasi).

Dalam kasus table view cells, GPU dapat bottlenecked dengan kompleks tampilan hierarki, karena bukan menghidupkan satu bitmap, itu adalah menghidupkan pandangan orang tua, dan melakukan subview tata letak perhitungan, render layer efek, dan compositing semua subviews. Jadi, bukannya menghidupkan satu bitmap, hal ini bertanggung jawab untuk hubungan dari sekelompok bitmap, dan bagaimana mereka berinteraksi, untuk piksel yang sama daerah.

Jadi, dalam ringkasan, alasan menggambar sel anda dalam satu tampilan dengan core grafis dapat mempercepat tabel bergulir TIDAK karena itu's gambar lebih cepat, tapi karena itu adalah mengurangi beban pada GPU, yang merupakan hambatan memberi anda kesulitan dalam skenario tertentu.

Komentar (1)

Saya seorang game developer, dan saya bertanya pertanyaan yang sama ketika teman saya mengatakan kepada saya bahwa saya UIImageView berdasarkan hirarki tampilan akan memperlambat permainan saya dan membuat hal yang mengerikan. Saya kemudian melanjutkan untuk meneliti segala sesuatu yang saya bisa menemukan tentang apakah untuk menggunakan UIViews, CoreGraphics, OpenGL atau sesuatu pihak ke-3 seperti Cocos2D. Konsisten jawaban yang saya dapatkan dari teman-teman, guru, dan insinyur Apple di WWDC adalah bahwa ada tidak't akan banyak perbedaan di akhir karena pada tingkat tertentu mereka semua melakukan hal yang sama. Tingkat yang lebih tinggi pilihan seperti UIViews bergantung pada tingkat yang lebih rendah pilihan seperti CoreGraphics dan OpenGL, hanya mereka dibungkus dalam kode untuk membuatnya lebih mudah bagi anda untuk menggunakan.

Don't menggunakan CoreGraphics jika anda hanya akan berakhir re-menulis UIView. Namun, anda bisa mendapatkan beberapa kecepatan dari menggunakan CoreGraphics, asalkan anda melakukan semua gambar anda dalam satu tampilan, tapi apakah itu benar-benar baiknya itu? Jawaban yang saya temukan adalah biasanya tidak ada. Ketika saya pertama kali memulai permainan saya, saya bekerja dengan iPhone 3G. Sebagai permainan saya tumbuh dalam kompleksitas, saya mulai melihat beberapa lag, tetapi dengan perangkat yang lebih baru itu benar-benar kentara. Sekarang aku punya banyak aksi yang terjadi, dan hanya tertinggal tampaknya penurunan 1-3 fps saat bermain di tingkat yang paling kompleks pada iPhone 4.

Masih saya memutuskan untuk menggunakan Instrumen untuk menemukan fungsi-fungsi yang mengambil sebagian besar waktu. Saya menemukan bahwa masalah yang tidak berhubungan dengan saya gunakan UIViews. Sebaliknya, ia berulang kali menelepon CGRectMake tertentu tabrakan penginderaan perhitungan dan loading gambar dan file audio terpisah untuk kelas-kelas tertentu yang sama-sama menggunakan gambar, bukan setelah mereka menarik dari salah satu pusat penyimpanan kelas.

Jadi pada akhirnya, anda mungkin dapat meraih sedikit keuntungan dari menggunakan CoreGraphics, tapi biasanya itu tidak akan layak atau mungkin tidak memiliki efek sama sekali. Satu-satunya waktu yang saya gunakan CoreGraphics adalah ketika menggambar bentuk-bentuk geometris daripada teks dan gambar.

Komentar (1)