Swift Generics (Part 2)

by Hoang Anh Tuan
461 views

Ở phần 1 của bài viết, bạn đã hiểu được Generic là gì, công dụng và cách sử dụng cơ bản của Generic.
Ở phần 2 của bài viết, bạn sẽ học được:

  • Extending a generic type.
  • Subclass a generic type.
  • Cách sử dụng generic nâng cao.

Extending a generic type.

Giả sử bạn có 1 struct Package như sau:

struct Package<Item> {
    var items = [Item]()
    mutating func push(item: Item) {
        items.append(item)
    }
    
    mutating func popLast() -> Item {
       return items.removeLast()
    }
}

Ở đây, Item là 1 generic. Khi bạn extending 1 generic type, bạn không cần khai báo lại <Item>. Item là kiểu dữ liệu generic đã được khai báo trong toàn bộ struct.

extension Package {
    var firstItem: Item? {
       return items.isEmpty ? nil : items[0]
    }
}

extension with a generic where clause

Giả sử bạn muốn khai báo func isFirstItem(:) như sau:

Lỗi này tương tự như ở phần 1, khi không phải mọi kiểu dữ liệu trong Swift đều có thể sử dụng toán tử (==) để so sánh. Vậy ở đây, bạn có thể extend generic với 1 mệnh đề where như sau:

Vì kiểu dữ liệu truyền vào của biến bPerson, mà Person thì không tuân theo Equatable, nên b không có func isFirstItem(:)

Note: Việc extend 1 generic type với mệnh đề where cho phép bạn thêm 1 điều kiện mới cho extension, vì vậy func isFirstItem(:) chỉ được thêm vào extension khi Item thuộc kiểu Equatable.

Generic subclass

Có 2 cách để kế thừa 1 class cha là kiểu generic như sau:

  • Tạo 1 class con kế thừa những thuộc tính và func của class cha nhưng vẫn giữ cho class con là kiểu generic.
  • Tạo 1 class con nhưng là 1 class cụ thể.

Ở trong ví dụ trên, dễ thấy:

  • Box là một generic subclass của class Package vì bạn muốn chiếc hộp này đựng được bất kì thứ gì, vì vậy Box vẫn là kiểu generic nên khi khởi tạo bạn phải truyền vào một kiểu dữ liệu cụ thể.
  • RosePackage là một subclass cụ thể của class Package, gói RosePackage này sẽ dùng chỉ để đựng hoa hồng.

Sử dụng generic nâng cao

Mọi table view cơ bản đều có các func sau:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
}
...

Trong trường hợp bạn muốn tạo các tableview khác nhau, thì sẽ dẫn đến việc duplicate các đoạn code này.
-> Sử dụng generic để giảm thiểu duplicate code.
Example1:

RoseTableViewController là 1 subclass cụ thể của 1 generic class.

Ở đây, bạn sử dụng generic để giảm duplicate code như sau:

  • Tạo 1 generic class tên BaseTableViewController chứa các thuộc tính, func cơ bản, và khai báo 1 placeholder T kiểu UITableViewCell để dễ dàng truyền các kiểu cell khác nhau vào.
  • Tạo 1 class RoseCell kiểu UITableViewCell.
  • Tạo class RoseTableViewController extends BaseTableViewController, class này dùng cell kiểu RoseCell nên chúng ta truyền kiểu RoseCell vào.
  • override lại các thuộc tính -> func numberOfRows tự thay đổi theo.

Example2 : Trong trường hợp bạn muốn mỗi cell có item kiểu dữ liệu bất kì, bạn có thể khai báo 1 class BaseCell kiểu generic, rồi khởi tạo các cell mới extends BaseCell.

Note: U ở phần khai báo BaseTableViewController và U ở phần khai báo BaseCell là khác nhau, ở đây mình đặt đều là U cho bạn đọc đỡ confuse.

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.