Làm thế nào để viết code gọn, rõ ràng và dễ đọc trong swift

1. Cẩn thận khi dùng trailing closure

Trailing closure là kiểu cú pháp trong swift cho phép chúng ta xóa bỏ những dấu ngoặc xung quanh parameter closure ở function, nhưng với điều kiện nó phải là paremeter cuối cùng. Chẳng hạn ta viết 1 hàm delay sử dụng dispatch after

func delay(time: TimeInterval, completionHandler: @escaping ()-> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + time) {
        completionHandler()
    }
}

Khi dùng ta chỉ việc gọi nó theo cách sau:

delay(time: 2.0) {
    // do something
}

Nhìn rất gọn và đẹp phải ko, nhưng ko phải lúc nào dùng trailing cũng đẹp như vậy trong 1 số trường hợp nó làm code của chúng ta trở nên rối mắt khó đọc hơn Ví dụ như khi ta viết 1 hàm login với parameters như sau:

typealias RequestSucceed = (jsonResponse: AnyObject) -> Void
typealias RequestFailed = (error: NSError, data: [String: AnyObject]?) -> Void
func loginWithParamters(parameters: JSONDictionary, success: RequestSucceed, failure: RequestFailed) {
}

Và khi sử dụng nó :

loginWithParamters(paramters, success: { (jsonResponse) in
    // handle success
}) { (error, data) in
    // handle error
 }

Việc sử dụng code như trên không báo lỗi nhưng nó làm cho code của chúng ta nhìn rất rối dài và khó debug, thay vào đó chúng ta có thể sử dụng đầy đủ các tên biến hoặc có thể tạo các closure riêng trong function như:

let success = {(jsonResponse: AnyObject) in
    // handle success
 }
        
let failure = {(error: NSError, data: [String, AnyObject]?) in
    // handle error
}
        
loginWithParamters(paramters, success: success, failure: failure)

Rõ ràng đoạn code thứ 2 làm cho chúng ta dễ nhìn, dễ debug hơn rất nhiều.

2. Sử dụng giá trị mặc định trong function

Giả sử chúng ta có 1 hàm show alert với title, message, 1 nút ok và action của nút ok:

func showAlert(title: String? = nil, message: String, okTitile: String, okAction:(() -> Swift.Void)?) {
	// setup alert here
}

Vấn đề là action của button ok không phải lúc nào chúng ta cũng cần sử dụng, vậy nên khi không sử dụng chúng ta sẽ viết

showAlert("Error", message: "Error message.", okTitile: "OK", okAction: nil)

Do đó ta có thể khai báo hàm show alert lại như sau:

func showAlert(title: String? = nil, message: String, okTitile: String, okAction:(() -> Swift.Void)? = nil) {
	// setup alert here
}

Khi gọi hàm showAlert mà không muốn setup action cho button ok chúng ta chỉ việc bỏ tham số okAction đi là xong

showAlert("Error", message: "Error message.", okTitile: "OK")

3. Gom nhóm object, method

Sử dụng // MARK: - để gom nhóm các object hay method liên quan đến nhau, hoặc có cùng mục đích sử dụng. Nếu không sử dụng MARK danh sách parameter và hàm của chúng ta trông như thế này

trông nó giống như 1 đống lộn xộn vậy. Còn nếu dùng MARK

Những hàm có cùng chức năng được gom nhóm lại với nhau trong sẽ gọn hơn cũng như dễ dang cho chúng ta tìm kiếm sau này.

4. Adopt ViewController theo protocol

Đã bao giờ mọi người viết 1 viewcontroller như thế này chưa ?

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, UISearchBarDelegate, CustomDelegate {
    // implement tableViewDelegate, textFieldDelegate, searchBarDelegate ... 
}

Code ViewController lúc này trở nên quá kồng kềnh khó đọc, thay vào đó chúng ta nên tách các delegate ra riêng như:

// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {
    // implement tableViewDataSource
}

// MARK: - UITableViewDelegate
extension ViewController: UITableViewDelegate {
    // implement tableViewDelegate
}

// MARK: - UITextFieldDelegate
extension ViewController: UITextFieldDelegate {
    // implement textFieldDelegate
}

// MARK: - UISearchBarDelegate
extension ViewController: UISearchBarDelegate {
    // implement searchBarViewDelegate
}

// MARK: - CustomDelegate
extension ViewController: CustomDelegate {
    // implement customDelegate
}

Rõ ràng tách các protocol ra thành từng phần như vậy nhìn rất thoáng, kể cả khi chúng ta tìm các function cũng trở nên rất dễ

5. Xoá những hàm hay đoạn code không dùng đến

Giả sử bạn nghiên cứu 1 sample code đọc đến hết 1 function để rồi khi search xem nó được sử dụng ở đâu thì bạn tá hoả nhận ra rằng nó chả đc gọi ở đâu cả, lúc đó chắc bạn sẽ muốn abcxyz cái thằng đã viết đoạn code này. Nên hãy xoá những đoạn code hoặc những biến mà bạn không được sử dụng đến trong chương trình để chẳng may có ai sau này đọc lại đoạn code đó họ ko phải mất công đọc 1 phần mà sẽ chẳng bao h đc sử dụng. Kể cả những hàm đã có sẵn khi chúng ta tạo file từ xocde ví dự như khi tạo 1 viewcontroller mới hàm

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

nó sẽ không được chúng ta sử dụng cho nên hãy xoá nó đi.