Làm swift toẹt vời trở lại

Dạo này thời tiết Hà Nội trở lạnh, post một bài cho nóng người :D. Lần này mình sẽ trình bày về một số tip để làm code trông swifty hơn.

defer

Sử dụng defer nếu như bạn là người hay quên :D. Tác dụng của defer là nó sẽ chạy sau khi hàm return.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    var x = 1
    func doDefer(_ value: inout Int) -> Int {
        // effect after return
        defer {
            value += 1
        }
        
        value += 1
        return value
    }
    
    print(doDefer(&x)) // 2
    print(x) // 3

Với tác dụng của hàm defer ta có thể tận dụng để giải phóng bộ nhớ, close file hay bất cứ tác vụ nào đòi hỏi 2 bước ràng buộc lúc bắt đầu và kết thúc.

Lazy

Sử dụng lazy trong trường hợp lấy ra một vài phần tử của mảng (lấy hết có khi phản tác dụng). Như ví dụ sau đây, ta filter như bình thường thì sẽ mất 11 bước tính toán, còn lazy mất 3 bước tính toán (test trên playground).

1
2
3
4
5
    let arr = [Int](1...10)
    _ = arr.filter{ $0 % 2 == 0 } // 11 times
    let lazy = arr.lazy.filter{ $0 % 2 == 0 } // 3 times
    lazy.first
    lazy.endIndex

Extension

Rất thích hợp dùng với Notification, ta tập hợp tất cả các key vào chung 1 file để quản lý.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
extension Notification.Name {
    typealias Nf = Notification.Name
    static let showMeTheCode = Nf("show me the code")
}

NotificationCenter.default.addObserver(
	###, 
	selector: ###, 
	name: .showMeTheCode, 
	object: nil)

Có thể áp dụng tương tượng với UserDefault.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
extension UserDefaults {
    struct Key: ExpressibleByStringLiteral {
        let drawValue: String
        init(stringLiteral value: StringLiteralType) {
            self.drawValue = value
        }
    }
}

extension UserDefaults {
    func value<T>(key: Key, as: T.Type? = nil) -> T? {
        return self.value(forKey: key.drawValue) as? T
    }
    
    func set(value: Any, forKey key: Key) {
        self.set(value, forKey: key.drawValue)
    }
}

extension UserDefaults.Key {
    typealias Key = UserDefaults.Key
    static let viewCounter: Key = "viewCounter" // ExpressibleByStringLiteral power :D
}

// Example
do {
    let usrDefault = UserDefaults.standard
    usrDefault.set(value: "aa", forKey: .viewCounter)
    if let x: String = usrDefault.value(key: .viewCounter) {
        print(x)
    }
}

Lưu ý để viết được là

static let viewCounter: Key = “viewCounter”

Ta phải sử dụng ExpressibleByStringLiteral