Trik Kinerja iOS Untuk Membuat Aplikasi Anda Lebih Berkinerja

Diterbitkan: 2022-03-10
Ringkasan cepat Performa yang baik sangat penting untuk memberikan pengalaman pengguna yang baik, dan pengguna iOS sering kali memiliki ekspektasi yang tinggi terhadap aplikasi mereka. Aplikasi yang lambat dan tidak responsif mungkin membuat pengguna berhenti menggunakan aplikasi Anda atau, lebih buruk lagi, memberikan peringkat yang buruk.

Meskipun perangkat keras iOS modern cukup kuat untuk menangani banyak tugas intensif dan kompleks, perangkat masih bisa terasa tidak responsif jika Anda tidak berhati-hati dengan kinerja aplikasi Anda. Pada artikel ini, kita akan membahas lima trik pengoptimalan yang akan membuat aplikasi Anda terasa lebih responsif.

1. Dequeue Sel yang Dapat Digunakan Kembali

Anda mungkin pernah menggunakan tableView.dequeueReusableCell(withIdentifier:for:) di dalam tableView(_:cellForRowAt:) sebelumnya. Pernah bertanya-tanya mengapa Anda harus mengikuti API yang canggung ini, alih-alih hanya memasukkan array sel? Mari kita pergi melalui alasan ini.

Katakanlah Anda memiliki tampilan tabel dengan seribu baris. Tanpa menggunakan sel yang dapat digunakan kembali, kita harus membuat sel baru untuk setiap baris, seperti ini:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // Create a new cell whenever cellForRowAt is called. let cell = UITableViewCell() cell.textLabel?.text = "Cell \(indexPath.row)" return cell }

Seperti yang mungkin Anda duga, ini akan menambahkan seribu sel ke memori perangkat saat Anda menggulir ke bawah. Bayangkan apa yang akan terjadi jika setiap sel berisi UIImageView dan banyak teks: Memuat semuanya sekaligus dapat menyebabkan aplikasi kehabisan memori! Selain itu, setiap sel akan membutuhkan memori baru untuk dialokasikan selama pengguliran. Jika Anda menggulir tampilan tabel dengan cepat, banyak memori kecil akan dialokasikan dengan cepat, dan proses ini akan membuat UI tersendat!

Untuk mengatasi ini, Apple telah memberi kami metode dequeueReusableCell(withIdentifier:for:) . Penggunaan kembali sel bekerja dengan menempatkan sel yang tidak lagi terlihat di layar ke dalam antrian, dan ketika sel baru akan terlihat di layar (misalnya, sel berikutnya di bawah saat pengguna menggulir ke bawah), tampilan tabel akan mengambil sel dari antrian ini dan memodifikasinya di metode cellForRowAt indexPath:

Mekanisme antrian penggunaan kembali sel
Cara kerja antrian penggunaan kembali sel di iOS (Pratinjau besar)

Dengan menggunakan antrian untuk menyimpan sel, tampilan tabel tidak perlu membuat seribu sel. Sebagai gantinya, dibutuhkan sel yang cukup untuk menutupi area tampilan tabel.

Dengan menggunakan dequeueReusableCell , kita dapat mengurangi memori yang digunakan oleh aplikasi dan membuatnya tidak mudah kehabisan memori!

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

2. Menggunakan Layar Peluncuran Yang Terlihat Seperti Layar Awal

Seperti disebutkan dalam Panduan Antarmuka Manusia (HIG) Apple, layar peluncuran dapat digunakan untuk meningkatkan persepsi respons aplikasi:

“Ini semata-mata dimaksudkan untuk meningkatkan persepsi bahwa aplikasi Anda cepat diluncurkan dan segera siap digunakan. Setiap aplikasi harus menyediakan layar peluncuran.”

Ini adalah kesalahan umum untuk menggunakan layar peluncuran sebagai layar pembuka untuk menunjukkan pencitraan merek atau untuk menambahkan animasi pemuatan. Rancang layar peluncuran agar identik dengan layar pertama aplikasi Anda, seperti yang disebutkan oleh Apple:

“Desain layar peluncuran yang hampir identik dengan layar pertama aplikasi Anda. Jika Anda menyertakan elemen yang terlihat berbeda saat aplikasi selesai diluncurkan, orang dapat mengalami kilatan yang tidak menyenangkan antara layar peluncuran dan layar pertama aplikasi.

“Layar peluncuran bukanlah peluang branding. Jangan mendesain pengalaman entri yang terlihat seperti layar pembuka atau jendela "Tentang". Jangan sertakan logo atau elemen pencitraan merek lainnya kecuali jika itu adalah bagian statis dari layar pertama aplikasi Anda.”

Menggunakan layar peluncuran untuk tujuan pemuatan atau pencitraan merek dapat memperlambat waktu penggunaan pertama dan membuat pengguna merasa bahwa aplikasi lamban.

Saat Anda memulai proyek iOS baru, LaunchScreen.storyboard kosong akan dibuat. Layar ini akan ditampilkan kepada pengguna saat aplikasi memuat pengontrol tampilan dan tata letak.

Untuk membuat aplikasi Anda terasa lebih cepat, Anda dapat mendesain layar peluncuran agar mirip dengan layar pertama (pengontrol tampilan) yang akan ditampilkan kepada pengguna.

Misalnya, layar peluncuran aplikasi Safari mirip dengan tampilan pertama:

Layar peluncuran dan tampilan pertama terlihat serupa
Perbandingan layar peluncuran dan tampilan pertama aplikasi Safari (Pratinjau besar)

Papan cerita layar peluncuran seperti file papan cerita lainnya, kecuali bahwa Anda hanya dapat menggunakan kelas UIKit standar, seperti UIViewController, UITabBarController, dan UINavigationController. Jika Anda mencoba menggunakan subkelas khusus lainnya (seperti UserViewController), Xcode akan memberi tahu Anda bahwa menggunakan nama kelas khusus dilarang.

Xcode menunjukkan kesalahan saat kelas khusus digunakan
Papan cerita layar peluncuran tidak boleh berisi kelas standar non-UIKit. (Pratinjau besar)

Hal lain yang perlu diperhatikan adalah bahwa UIActivityIndicatorView tidak bernyawa saat ditempatkan di layar peluncuran, karena iOS akan menghasilkan gambar statis dari papan cerita layar peluncuran dan menampilkannya kepada pengguna. (Hal ini disebutkan secara singkat dalam presentasi WWDC 2014 “Platform State of the Union”, sekitar 01:21:56 .)

HIG Apple juga menyarankan kami untuk tidak menyertakan teks pada layar peluncuran kami, karena layar peluncuran statis, dan Anda tidak dapat melokalkan teks untuk memenuhi bahasa yang berbeda.

Bacaan yang disarankan : Aplikasi Seluler Dengan Fitur Pengenalan Wajah: Cara Membuatnya Nyata

3. Pemulihan Status Untuk Pengontrol Tampilan

Pelestarian dan pemulihan status memungkinkan pengguna untuk kembali ke status UI yang sama persis dari sebelum mereka meninggalkan aplikasi. Terkadang, karena memori yang tidak mencukupi, sistem operasi mungkin perlu menghapus aplikasi Anda dari memori saat aplikasi berada di latar belakang, dan aplikasi mungkin kehilangan jejak status UI terakhirnya jika tidak dipertahankan, yang mungkin menyebabkan pengguna kehilangan pekerjaannya. sedang berlangsung!

Di layar multitasking, kita bisa melihat daftar aplikasi yang telah di-background. Kami mungkin berasumsi bahwa aplikasi ini masih berjalan di latar belakang; pada kenyataannya, beberapa aplikasi ini mungkin terbunuh dan dimulai ulang oleh sistem karena tuntutan memori. Snapshot aplikasi yang kita lihat dalam tampilan multitasking sebenarnya adalah screenshot yang diambil oleh sistem dari kanan saat kita keluar dari aplikasi (yaitu untuk membuka layar beranda atau multitasking).

iOS membuat ilusi aplikasi yang berjalan di latar belakang dengan mengambil tangkapan layar dari tampilan terbaru
Tangkapan layar aplikasi yang diambil oleh iOS saat pengguna keluar dari aplikasi (Pratinjau besar)

iOS menggunakan tangkapan layar ini untuk memberikan ilusi bahwa aplikasi masih berjalan atau masih menampilkan tampilan khusus ini, sedangkan aplikasi mungkin telah dihentikan atau dimulai ulang di latar belakang sambil tetap menampilkan tangkapan layar yang sama.

Pernahkah Anda mengalami, saat melanjutkan aplikasi dari layar multitasking, bahwa aplikasi tersebut menunjukkan antarmuka pengguna yang berbeda dari snapshot yang ditampilkan dalam tampilan multitasking? Ini karena aplikasi belum menerapkan mekanisme pemulihan status, dan data yang ditampilkan hilang saat aplikasi dimatikan di latar belakang. Hal ini dapat menyebabkan pengalaman buruk karena pengguna mengharapkan aplikasi Anda dalam keadaan yang sama seperti saat mereka meninggalkannya.

Dari artikel Apple:

“Mereka mengharapkan aplikasi Anda dalam keadaan yang sama seperti ketika mereka meninggalkannya. Pelestarian dan pemulihan status memastikan bahwa aplikasi Anda kembali ke status sebelumnya saat diluncurkan lagi.”

UIKit melakukan banyak pekerjaan untuk menyederhanakan pelestarian dan pemulihan status bagi kami: UIKit menangani penyimpanan dan pemuatan status aplikasi secara otomatis pada waktu yang tepat. Yang perlu kita lakukan hanyalah menambahkan beberapa konfigurasi untuk memberi tahu aplikasi untuk mendukung pelestarian dan pemulihan status dan untuk memberi tahu aplikasi data apa yang perlu dipertahankan.

Untuk mengaktifkan penyimpanan dan pemulihan status, kita dapat menerapkan dua metode ini di AppDelegate.swift :

 func application(_ application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool { return true }
 func application(_ application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool { return true }

Ini akan memberi tahu aplikasi untuk menyimpan dan memulihkan status aplikasi secara otomatis.

Selanjutnya, kami akan memberi tahu aplikasi pengontrol tampilan mana yang perlu dipertahankan. Kami melakukan ini dengan menentukan "ID Pemulihan" di storyboard:

Mengatur ID pemulihan di storyboard
Menyetel ID pemulihan di storyboard (Pratinjau besar)

Anda juga dapat mencentang “Gunakan ID Storyboard” untuk menggunakan ID storyboard sebagai ID pemulihan.

Untuk mengatur ID restorasi dalam kode, kita dapat menggunakan properti restorationIdentifier dari pengontrol tampilan.

 // ViewController.swift self.restorationIdentifier = "MainVC"

Selama pelestarian status, pengontrol tampilan atau tampilan apa pun yang telah ditetapkan sebagai pengenal pemulihan akan menyimpan statusnya ke disk.

Pengidentifikasi restorasi dapat dikelompokkan bersama untuk membentuk jalur restorasi. Pengidentifikasi dikelompokkan menggunakan hierarki tampilan, dari pengontrol tampilan root hingga pengontrol tampilan aktif saat ini. Misalkan MyViewController disematkan di pengontrol navigasi, yang disematkan di pengontrol bilah tab lain. Dengan asumsi mereka menggunakan nama kelas mereka sendiri sebagai pengidentifikasi restorasi, jalur restorasi akan terlihat seperti ini:

 TabBarController/NavigationController/MyViewController

Saat pengguna meninggalkan aplikasi dengan MyViewController sebagai pengontrol tampilan aktif, jalur ini akan disimpan oleh aplikasi; maka aplikasi akan mengingat hierarki tampilan sebelumnya yang ditampilkan ( Pengontrol Tab BarPengontrol Navigasi → Pengontrol Tampilan Saya ).

Setelah menetapkan pengidentifikasi restorasi, kita perlu mengimplementasikan metode encodeRestorableState(with coder:) dan decodeRestorableState(with coder:) untuk setiap view controller yang diawetkan. Kedua metode ini mari kita tentukan data apa yang perlu disimpan atau dimuat dan bagaimana mengkodekan atau mendekodekannya.

Mari kita lihat pengontrol tampilan:

 // MyViewController.swift​ // MARK: State restoration // UIViewController already conforms to UIStateRestoring protocol by default extension MyViewController { // will be called during state preservation override func encodeRestorableState(with coder: NSCoder) { // encode the data you want to save during state preservation coder.encode(self.username, forKey: "username") super.encodeRestorableState(with: coder) } // will be called during state restoration override func decodeRestorableState(with coder: NSCoder) { // decode the data saved and load it during state restoration if let restoredUsername = coder.decodeObject(forKey: "username") as? String { self.username = restoredUsername } super.decodeRestorableState(with: coder) } }

Ingatlah untuk memanggil implementasi superclass di bagian bawah metode Anda sendiri. Ini memastikan bahwa kelas induk memiliki kesempatan untuk menyimpan dan memulihkan status.

Setelah objek selesai didekode, applicationFinishedRestoringState() akan dipanggil untuk memberi tahu pengontrol tampilan bahwa status telah dipulihkan. Kami dapat memperbarui UI untuk pengontrol tampilan dalam metode ini.

 // MyViewController.swift​ // MARK: State restoration // UIViewController already conforms to UIStateRestoring protocol by default extension MyViewController { ... override func applicationFinishedRestoringState() { // update the UI here self.usernameLabel.text = self.username } }

Di sana Anda memilikinya! Ini adalah metode penting untuk menerapkan pelestarian dan pemulihan status untuk aplikasi Anda. Perlu diingat bahwa sistem operasi akan menghapus status tersimpan saat aplikasi ditutup paksa oleh pengguna, untuk menghindari terjebak dalam status rusak jika terjadi kesalahan dalam pelestarian dan pemulihan status.

Juga, jangan simpan data model apa pun (yaitu data yang seharusnya disimpan ke UserDefaults atau Data Inti) ke status, meskipun mungkin tampak nyaman untuk melakukannya. Data status akan dihapus saat pengguna memaksa keluar dari aplikasi Anda, dan Anda tentu tidak ingin kehilangan data model dengan cara ini.

Untuk menguji apakah pelestarian dan pemulihan status berfungsi dengan baik, ikuti langkah-langkah di bawah ini:

  1. Bangun dan luncurkan aplikasi menggunakan Xcode.
  2. Navigasikan ke layar dengan pelestarian dan pemulihan status yang ingin Anda uji.
  3. Kembali ke layar beranda (dengan menggesek ke atas atau mengeklik dua kali tombol beranda, atau menekan Shift + Cmd + H di simulator) untuk mengirim aplikasi ke latar belakang.
  4. Hentikan aplikasi di Xcode dengan menekan tombol.
  5. Luncurkan aplikasi lagi dan periksa apakah status telah berhasil dipulihkan.

Karena bagian ini hanya mencakup dasar-dasar pelestarian dan pemulihan keadaan, saya merekomendasikan artikel berikut dari Apple Inc. untuk pengetahuan yang lebih mendalam tentang pemulihan keadaan:

  1. Melestarikan Dan Memulihkan Negara
  2. Proses Pelestarian UI
  3. Proses Pemulihan UI

4. Kurangi Penggunaan Tampilan Non-Buram Sebanyak Mungkin

Tampilan buram adalah tampilan yang tidak memiliki transparansi, artinya setiap elemen UI yang ditempatkan di belakangnya tidak terlihat sama sekali. Kita dapat mengatur tampilan menjadi buram di Interface Builder:

Ini akan memberi tahu sistem gambar untuk melewatkan menggambar apa pun yang ada di balik tampilan ini
Setel UIView menjadi buram di storyboard (Pratinjau besar)

Atau kita dapat melakukannya secara terprogram dengan properti isOpaque dari UIView:

 view.isOpaque = true

Menyetel tampilan ke buram akan membuat sistem gambar mengoptimalkan beberapa kinerja gambar saat merender layar.

Jika tampilan memiliki transparansi (yaitu alfa di bawah 1.0), maka iOS harus melakukan pekerjaan ekstra untuk menghitung apa yang harus ditampilkan dengan memadukan lapisan tampilan yang berbeda dalam hierarki tampilan. Di sisi lain, jika tampilan diatur ke buram, maka sistem gambar hanya akan menempatkan tampilan ini di depan dan menghindari kerja ekstra untuk memadukan beberapa lapisan tampilan di belakangnya.

Anda dapat memeriksa lapisan mana yang sedang dicampur (tidak buram) di Simulator iOS dengan memeriksa DebugColor Blended Layers .

Hijau adalah campuran non-warna, merah adalah lapisan campuran
Tampilkan lapisan campuran warna di Simulator

Setelah memeriksa opsi Color Blended Layers , Anda dapat melihat bahwa beberapa tampilan berwarna merah dan beberapa berwarna hijau. Merah menunjukkan bahwa tampilan tidak buram dan tampilan outputnya adalah hasil dari lapisan yang tercampur di belakangnya. Hijau menunjukkan bahwa tampilan buram dan tidak ada pencampuran yang dilakukan.

Dengan latar belakang warna buram, lapisan tidak perlu berbaur dengan lapisan lain
Tetapkan warna latar belakang non-transparan ke UILabel bila memungkinkan untuk mengurangi lapisan campuran warna. (Pratinjau besar)

Label yang ditampilkan di atas (“Lihat Teman”, dll.) disorot dengan warna merah karena ketika label diseret ke storyboard, warna latar belakangnya disetel ke transparan secara default. Saat sistem gambar menyusun tampilan di dekat area label, sistem akan meminta lapisan di belakang label dan melakukan beberapa perhitungan.

Salah satu cara Anda dapat mengoptimalkan kinerja aplikasi adalah dengan mengurangi jumlah tampilan yang disorot dengan warna merah sebanyak mungkin.

Dengan mengubah label.backgroundColor = UIColor.clear menjadi label.backgroundColor = UIColor.white , kita dapat mengurangi pencampuran lapisan antara label dan lapisan tampilan di belakangnya.

Menggunakan warna latar belakang transparan akan menyebabkan pencampuran lapisan
Banyak label disorot dengan warna merah karena warna latar belakangnya transparan, menyebabkan iOS menghitung warna latar belakang dengan memadukan tampilan di belakangnya. (Pratinjau besar)

Anda mungkin telah memperhatikan bahwa, meskipun Anda telah menyetel UIImageView menjadi buram dan menetapkan warna latar belakang, simulator akan tetap menampilkan warna merah pada tampilan gambar. Ini mungkin karena gambar yang Anda gunakan untuk tampilan gambar memiliki saluran alfa.

Untuk menghapus saluran alfa untuk sebuah gambar, Anda dapat menggunakan aplikasi Pratinjau untuk membuat duplikat gambar ( Shift + Cmd + S ), dan hapus centang pada kotak centang "Alpha" saat menyimpan.

Hapus centang pada kotak centang 'Alfa' saat menyimpan gambar untuk membuang saluran alfa.
Hapus centang pada kotak centang 'Alpha' saat menyimpan gambar untuk membuang saluran alfa. (Pratinjau besar)

5. Meneruskan Fungsi Pemrosesan Berat ke Thread Latar Belakang (GCD)

Karena UIKit hanya berfungsi di utas utama, melakukan pemrosesan berat di utas utama akan memperlambat UI. Utas utama digunakan oleh UIKit tidak hanya untuk menangani dan menanggapi masukan pengguna, dan juga untuk menggambar layar.

Kunci untuk membuat aplikasi menjadi responsif adalah dengan memindahkan sebanyak mungkin tugas pemrosesan yang berat ke utas latar belakang. Hindari melakukan perhitungan yang rumit, jaringan, dan operasi IO yang berat (misalnya membaca dan menulis ke disk) pada thread utama.

Anda mungkin pernah menggunakan aplikasi yang tiba-tiba menjadi tidak responsif terhadap input sentuh Anda, dan rasanya seperti aplikasi telah macet. Ini kemungkinan besar disebabkan oleh aplikasi yang menjalankan tugas komputasi berat di utas utama.

Utas utama biasanya bergantian antara tugas UIKit (seperti menangani input pengguna) dan beberapa tugas ringan dalam interval kecil. Jika tugas berat berjalan di utas utama, maka UIKit perlu menunggu hingga tugas berat selesai sebelum dapat menangani input sentuh.

Hindari menjalankan tugas yang intensif kinerja atau memakan waktu di utas utama
Berikut adalah cara utas utama menangani tugas UI dan mengapa hal itu menyebabkan UI macet saat tugas berat dilakukan. (Pratinjau besar)

Secara default, kode di dalam metode siklus hidup pengontrol tampilan (seperti viewDidLoad) dan fungsi IBOutlet dijalankan di utas utama. Untuk memindahkan tugas pemrosesan yang berat ke utas latar belakang, kita dapat menggunakan antrean Grand Central Dispatch yang disediakan oleh Apple.

Berikut template untuk berpindah antrian:

 // Switch to background thread to perform heavy task. DispatchQueue.global(qos: .default).async { // Perform heavy task here. // Switch back to main thread to perform UI-related task. DispatchQueue.main.async { // Update UI. } }

qos adalah singkatan dari “kualitas pelayanan”. Nilai kualitas layanan yang berbeda menunjukkan prioritas yang berbeda untuk tugas yang ditentukan. Sistem operasi akan mengalokasikan lebih banyak waktu CPU dan throughput I/O daya CPU untuk tugas yang dialokasikan dalam antrian dengan nilai QoS yang lebih tinggi, yang berarti bahwa tugas akan selesai lebih cepat dalam antrian dengan nilai QoS yang lebih tinggi. Nilai QoS yang lebih tinggi juga akan mengkonsumsi lebih banyak energi karena menggunakan lebih banyak sumber daya.

Berikut daftar nilai QoS dari prioritas tertinggi hingga terendah:

Nilai kualitas layanan antrian diurutkan berdasarkan kinerja dan efisiensi energi
Nilai kualitas layanan antrian diurutkan berdasarkan kinerja dan efisiensi energi (Pratinjau besar)

Apple telah menyediakan tabel praktis dengan contoh nilai QoS yang digunakan untuk tugas yang berbeda.

Satu hal yang perlu diingat adalah bahwa semua kode UIKit harus selalu dieksekusi di utas utama. Memodifikasi objek UIKit (seperti UILabel dan UIImageView ) di utas latar belakang dapat memiliki konsekuensi yang tidak diinginkan, seperti UI tidak benar-benar diperbarui, terjadi kerusakan, dan sebagainya.

Dari artikel Apple:

“Memperbarui UI di utas selain utas utama adalah kesalahan umum yang dapat mengakibatkan pembaruan UI yang terlewat, cacat visual, kerusakan data, dan mogok.”

Saya merekomendasikan menonton video Apple WWDC 2012 pada konkurensi UI untuk lebih memahami cara membangun aplikasi yang responsif.

Catatan

Keuntungan dari pengoptimalan kinerja adalah Anda harus menulis lebih banyak kode atau mengonfigurasi pengaturan tambahan di atas fungsionalitas aplikasi. Ini mungkin membuat aplikasi Anda dikirimkan lebih lambat dari yang diharapkan, dan Anda akan memiliki lebih banyak kode untuk dipelihara di masa mendatang, dan lebih banyak kode berarti berpotensi lebih banyak bug.

Sebelum menghabiskan waktu untuk mengoptimalkan aplikasi Anda, tanyakan pada diri Anda apakah aplikasi tersebut sudah lancar atau ada bagian yang tidak responsif yang benar-benar perlu dioptimalkan. Menghabiskan banyak waktu untuk mengoptimalkan aplikasi yang sudah lancar untuk mengurangi 0,01 detik mungkin tidak sepadan, karena waktu dapat dihabiskan dengan lebih baik untuk mengembangkan fitur yang lebih baik atau prioritas lainnya.

Sumber Daya Lebih Lanjut

  • “Suite Permen Mata iOS yang Lezat,” Tim Oliver, Tokyo iOS Meetup 2018 (Video)
  • “Membangun Antarmuka Pengguna Bersamaan di iOS,” Andy Matuschak, WWDC 2012 (Video)
  • “Melestarikan UI Aplikasi Anda di Seluruh Peluncuran,” Apple
  • “Panduan Pemrograman Konkurensi: Antrian Pengiriman,” Arsip Dokumentasi, Apple
  • “Pemeriksa Utas Utama,” Apple