Bayangkan sebuah buku di mana tidak ada pembagian menjadi beberapa bab, dan semuanya berjalan tanpa gangguan logis dan semantik, sebuah buku di mana tidak ada paragraf, tidak ada titik dan koma, sebuah buku di mana baris pertama menceritakan tentang satu hal, yang kedua tentang yang lain, yang ketiga lagi tentang hal pertama.
Disajikan?
Bisakah Anda mengerti tentang apa buku itu?
Seberapa cepat Anda dapat menemukan bagian yang Anda minati?
Kode Anda, serta isi buku itu, perlu disusun agar kode itu mudah dibaca dan menyampaikan makna di dalamnya.
Pada artikel ini saya akan menunjukkan contoh kode pengorganisasian di mana kelas akan memiliki urutan blok utama yang sama dan rinciannya.
Untuk kenyamanan, saya akan menggunakan kelas kata (kelas), tetapi menyiratkan jenis apa pun (kelas, struct, enum).
Berkat penerapan tip-tip ini, kode Anda akan dapat dibaca, yang di masa depan akan memberikan kemudahan dan kecepatan bekerja dengannya.
Tentu saja, tips yang dijelaskan dapat ditingkatkan sesuai dengan keinginan Anda, dengan memperhatikan prinsip-prinsip dasar.
Pertama, mari kita bandingkan kode yang sama dalam dua cara.
Contoh kelas yang berantakan:
| final class MessyViewController: UIViewController { |
| |
| private let userService = UserService() |
| var userID: String? |
| private var userList: [User]? |
| |
| @IBOutlet private weak var searchBar: UISearchBar! |
| |
| weak var delegate: SomeDelegate? |
| |
| @IBAction private func cancelButtonPressed(_ sender: UIBarButtonItem) { |
| dismiss(animated: true, completion: nil) |
| } |
| |
| override func viewDidLoad() { |
| super.viewDidLoad() |
| // Do any additional setup after loading the view. |
| navigationController?.navigationBar.backgroundColor = .red |
| navigationItem.title = "Some" |
| } |
| @IBOutlet private weak var tableView: UITableView! |
| } |
Kode ini mirip dengan kumpulan metode, variabel, dan outlet, di mana semuanya bergabung bersama, sulit untuk memahami apa yang dimaksud dan di tempat apa yang harus dicari.
Contoh kelas murni:
| final class CleanViewController: UIViewController { |
| |
| // MARK: - IBOutlets |
| |
| @IBOutlet private weak var searchBar: UISearchBar! |
| @IBOutlet private weak var tableView: UITableView! |
| |
| // MARK: - Public Properties |
| |
| var userID: String? |
| weak var delegate: SomeDelegate? |
| |
| // MARK: - Private Properties |
| |
| private let userService = UserService() |
| private var userList: [User]? |
| |
| // MARK: - Lifecycle |
| |
| override func viewDidLoad() { |
| super.viewDidLoad() |
| |
| setupNavigationBar() |
| } |
| |
| // MARK: - Private Methods |
| |
| private func setupNavigationBar() { |
| navigationController?.navigationBar.backgroundColor = .red |
| navigationItem.title = "Some" |
| } |
| |
| // MARK: - IBActions |
| |
| @IBAction private func cancelButtonPressed(_ sender: UIBarButtonItem) { |
| dismiss(animated: true, completion: nil) |
| } |
| |
| } |
Baris kosong 38 - indentasi satu baris dari metode terakhir sehingga Anda dapat melihat di mana braket penutupan terakhir dari metode berakhir dan di mana kelas berakhir.
Fungsionalitas yang sama ditunjukkan pada kedua contoh, tetapi perbedaannya adalah bahwa opsi kedua memiliki struktur yang jelas, karena logikanya lebih jelas, kodenya mudah dibaca, Anda dapat dengan cepat menemukan apa yang Anda cari di dalamnya, dan di samping itu, hanya bagus untuk dilihat.
Prinsip dasar untuk pembentukan struktur kelas murni:
- Selalu gunakan // MARK: -
- Berikan nama label dan tetapkan prioritasnya
- Menempatkan logika dari metode siklus hidup ke dalam metode terpisah
- Kami menggunakan ekstensi untuk mengimplementasikan protokol
- Pilih Elemen Terkait Secara Logika
- Kami menghapus yang tidak digunakan
- Otomatiskan rutin
1. Selalu gunakan // MARK: -
Untuk memudahkan membaca, buku ini dibagi menjadi beberapa bab, dan akan lebih nyaman bagi kita untuk bekerja jika kita membuat daftar isi kelas menggunakan
// MARK: - .
Label ini tidak hanya menonjol dari seluruh kode, tetapi juga secara otomatis membuat daftar isi - label ini menyoroti bagian-bagian dalam kode yang dicetak tebal dalam daftar elemen file ini.
Anda dapat melihat daftar isi file dengan mengklik tombol setelah panah kanan (>) di bagian paling atas file setelah nama file ini atau ctr + 6 (menu item dokumen).2. Kami memberi nama label dan kami menetapkan urutannya
Di bawah ini adalah label utama untuk memecah kode menjadi blok yang terhubung secara logis dan urutannya:
| // MARK: - IBOutlets |
| |
| // MARK: - Public Properties |
| |
| // MARK: - Private Properties |
| |
| // MARK: - Initializers |
| |
| // MARK: - Lifecycle |
| |
| // MARK: - Public Methods |
| |
| // MARK: - Private Methods |
| |
| // MARK: - IBActions |
Saat menggunakan metode pengelompokan ini, seseorang dapat dengan mudah menavigasi dalam kode kelas apa pun.
3. Tarik logika dari metode siklus hidup ke metode terpisah
Logika di dalam metode siklus hidup ViewController harus dimasukkan ke dalam metode terpisah, bahkan jika Anda harus membuat metode dengan satu baris kode. Hari ini adalah satu, dan besok adalah sepuluh.
| ❌ NOT Preferred |
| |
| override func viewDidLoad() { |
| super.viewDidLoad() |
| |
| navigationController?.navigationBar.backgroundColor = .red |
| someButton.layer.cornerRadius = 10 |
| someButton.layer.masksToBounds = true |
| navigationItem.title = "Some" |
| print("Some") |
| } |
| |
| |
| ✅ Preferred |
| |
| // MARK: - Lifecycle |
| |
| override func viewDidLoad() { |
| super.viewDidLoad() |
| |
| setupNavigationBar() |
| setupSomeButton() |
| printSome() |
| } |
| |
| |
| // MARK: - Private Methods |
| |
| private func setupNavigationBar() { |
| navigationController?.navigationBar.backgroundColor = .red |
| navigationItem.title = "Some" |
| } |
| |
| private func setupSomeButton() { |
| someButton.layer.cornerRadius = 10 |
| someButton.layer.masksToBounds = true |
| } |
| |
| private func printSome() { |
| print("Some") |
| } |
Karena kenyataan bahwa detail implementasi di-outsourcing-kan ke metode pihak ketiga, logika siklus hidup menjadi lebih jelas.
4. Gunakan ekstensi untuk mengimplementasikan protokol
Keluarkan implementasi protokol dalam ekstensi bertanda
// MARK: - SomeProtocol :
| ❌ NOT Preferred |
| |
| final class CleanViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { |
| |
| // all methods |
| } |
| |
| |
| ✅ Preferred |
| |
| final class CleanViewController: UIViewController { |
| |
| // class stuff here |
| |
| } |
| |
| |
| // MARK: - Table View Data Source |
| extension CleanViewController: UITableViewDataSource { |
| |
| func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
| |
| return userList?.count ?? 0 |
| } |
| |
| func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
| |
| let cell = UITableViewCell() |
| return cell |
| } |
| |
| } |
Label ini akan berisi semua yang terkait dengan protokol ini - semua yang ada di sini dan tidak perlu pergi ke tempat lain, jika tidak, metode dan properti protokol akan tersebar di seluruh kelas.
5. Pilih elemen yang berhubungan secara logis
Untuk meningkatkan visibilitas, perlu untuk memilih elemen yang berhubungan secara logis menggunakan garis kosong:
| ❌ NOT Preferred |
| |
| private func showActivityIndicator(on viewController: UIViewController) { |
| activityIndicator.center = viewController.view.center |
| loadingView.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) |
| loadingView.alpha = 0.5 |
| activityIndicator.hidesWhenStopped = true |
| activityIndicator.style = .whiteLarge |
| loadingView.center = viewController.view.center |
| loadingView.clipsToBounds = true |
| loadingView.layer.cornerRadius = 15 |
| viewController.view.addSubview(loadingView) |
| viewController.view.addSubview(activityIndicator) |
| activityIndicator.startAnimating() |
| } |
| |
| |
| ✅ Preferred |
| |
| private func showActivityIndicator(on viewController: UIViewController) { |
| activityIndicator.center = viewController.view.center |
| activityIndicator.hidesWhenStopped = true |
| activityIndicator.style = .whiteLarge |
| |
| loadingView.center = viewController.view.center |
| loadingView.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) |
| loadingView.alpha = 0.5 |
| loadingView.clipsToBounds = true |
| loadingView.layer.cornerRadius = 15 |
| |
| viewController.view.addSubview(loadingView) |
| viewController.view.addSubview(activityIndicator) |
| |
| activityIndicator.startAnimating() |
| } |
6. Kami menghapus yang tidak digunakan
Jangan meninggalkan komentar yang tidak perlu (default), metode kosong atau fungsionalitas mati - ini menyumbat kode. Perhatikan kelas AppDelegate, kemungkinan besar Anda akan menemukan metode kosong di sana dengan komentar di dalamnya.
| ❌ NOT Preferred |
| |
| @UIApplicationMain |
| class AppDelegate: UIResponder, UIApplicationDelegate { |
| |
| var window: UIWindow? |
| |
| |
| func application( |
| _ application: UIApplication, |
| didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { |
| // Override point for customization after application launch. |
| return true |
| } |
| // |
| // func someFunc() { |
| // print("Some") |
| // } |
| |
| func applicationWillResignActive(_ application: UIApplication) { |
| // Sent when the application is about to move from active to inactive state. This can occur for certain |
| //types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits |
| //the application and it begins the transition to the background state. |
| // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. |
| } |
| |
| |
| ✅ Preferred |
| |
| @UIApplicationMain |
| class AppDelegate: UIResponder, UIApplicationDelegate { |
| |
| var window: UIWindow? |
| |
| |
| func application( |
| _ application: UIApplication, |
| didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { |
| |
| return true |
| } |
| |
| } |
7. Otomatisasi rutin
Untuk menghindari penulisan secara manual di setiap kelas
// MARK: - SomeMark , gunakan
Cuplikan Kode .
Kami menulis label, pilih labelnya, lalu Editor -> Buat Cuplikan Kode, beri nama, lalu panggil pintasan.// MARK: - Bonus
- Tandai kelas dengan kata kunci terakhir jika kelas ini tidak memiliki anak - proyek mengkompilasi lebih cepat dan kode berjalan lebih cepat.
- Tandai properti, outlet, dan metode dengan kata kunci pribadi - mereka hanya akan tersedia di dalam kelas dan tidak akan ada di daftar properti dan metode publik jika tidak diperlukan di sana.
Saya berharap Anda setiap keberhasilan dalam pengembangan aplikasi dan biarkan kelas Anda menjadi lebih bersih!
// MARK: - Bantuan dalam menulis artikelSergey Pchelyakov
Alexey Pleshkov
AlekseyPleshkov// MARK: - TautanRay gaya kode wenderlich