07/09/2018, 17:12

Swift - Closure: Bài 2: CallBack/ Completion (Part 1)

Swift - Closure: Bài 2: CallBack/ Completion (Part 1) Trước khi mình vào bài này mình xin giới thiệu các bài 1 nguồn học Swift cực kì hay, đó là Kilo loco youtuber. Các bạn có thể search. 1. Đặt chủ đề Vào chủ đề, callback functions trong Swift và cách sử dụng chúng khi làm việc ở background ...

Swift - Closure: Bài 2: CallBack/ Completion (Part 1)

Trước khi mình vào bài này mình xin giới thiệu các bài 1 nguồn học Swift cực kì hay, đó là Kilo loco youtuber. Các bạn có thể search.

1. Đặt chủ đề
Vào chủ đề, callback functions trong Swift và cách sử dụng chúng khi làm việc ở background thread. Mình sẽ nói rõ toàn bộ callback functions (completion handlers) hoạt động như thế nào và tại sao nên dùng chúng, cách đảm bảo completion handler được hoạt động trên main thread.

Callbacks là phần chính khi làm việc với networking như URLSession hay Alamofire v..v, nhưng bạn cần có 1 vài kiến thức về cách hoạt động của các thread và tại sao trả về main queue lại quan trọng. Mình sẽ tạo 1 app khá đơn giản, load dữ liệu data lên tableView. Note trước, mình sẽ tạo 1 file JSON với data JSON tự tạo, các bạn tự tạo 1 file JSON nhé, có id, name, vài thuộc tính nhỏ nhỏ.

2. Callback/ Completion không tham số
Bước 1: Để đi nhanh, mình tạo tableView và setup cell cho nó dựa trên 1 mảng String. Phần này dễ mình không đề cập nhiều. Các bạn có thể xem sơ qua:
alt text
Bây giờ ta cần load dữ liệu từ data lên, phần load JSON mình cũng đã có viết rất nhiều cách load json. Các bạn có thể vào facebook Chia Sẻ Swift để xem kĩ hơn.

Bước 2: Load dữ liệu từ file JSON lên, phần này mình chỉ show lại code:
alt text

Nào bây giờ run thử và ta thấy dữ liệu json đã được trả về:
alt text

Bây giờ ta chỉ muốn lấy name của các phần tử trong list json trả về, code như sau:
alt text

Kết quả sẽ là:
alt text

OK BẮT ĐẦU
Bây giờ ta vào phần callback, callback là gì? Đó là một closure, được dùng như một parameter trong main function của bạn. Khi bạn gọi closure đó bên trong function của bạn, nó cho phép bạn viết nhiều code hơn tại nơi bạn thực sự sử dụng nó. Bạn thấy rối chưa chứ mình thấy rối rồi đó. Mình sẽ giải thích rõ hơn khi code.

Ta muốn có những cái tên này được truyền qua qua đây (tại VC này) đến mảng names của mình. Nhưng vấn đề là thường đoạn này không nằm bên trong VC này như đoạn code này. Xin lỗi mọi người, đây là 1 bad practice nếu xử lý networking, coi như mình nợ, mình sẽ có practice tốt hơn ở bài 3. Thường đoạn xử lý code này thường nằm ở file khác (thường là Service or ViewModel) mà ta không có ở đây. Thông thường, bạn sẽ dùng callback, callback thì nó cũng kiểu như completion, nếu các bạn thấy trong phần networking mà có completion thì các bạn hiểu đó là callback

Nên ta sẽ cứ làm theo những gì các tiền bối đã làm, same thing, same pattern, và truyền vào hàm getPeople() một parameter là 1 closure, đặt tên là completion như sau:

func getPeople(completion: () -> Void) {
    guard let path = Bundle.main.path(forResource: "someJson", ofType: "json") else { return }
    let url = URL(fileURLWithPath: path)
    do {
      let data = try Data(contentsOf: url)
      let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
      guard let array = json as? [[String: Any]] else { return }
      var names = [String]()
      for user in array {
        guard let name = user["name"] as? String else { continue }
        names.append(name)
      }
//      print(names)
      completion()
    } catch {
      print(error)
    }
  }

Các bạn để ý 2 dòng code sau:

func getPeople(completion: () -> Void)

// print(names)
completion()

Cái ta sẽ làm ở đây là truyền vào 1 hàm và không cần trả lại gì hết (chỉ cần print ra thôi). Bây giờ ta call completion() bên trong hàm chính của mình. Và ta gọi lại hàm getPeople ở viewDidLoad(). Lúc ta, viết rara, thì ta có thể thấy nó hiển thị ở autocompletion:
alt text

Việc tiếp theo là ta in ra đại 1 chữ gì đó, và xem thử completion working như thế nào:
alt text

Nó hiển thị Hello world. Ok, mình xin tóm tắt lại như sau:

Closure là 1 function được dùng như 1 parameter trong 1 function lớn hơn, mà khi ta dùng function lớn hơn đó, ta có thể code thêm tuỳ ý tại nơi mà ta gọi function lớn đó nhờ vào closure.
Ở ví dụ này, function lớn là getPeople(), nó làm các việc bên trong + completion(). Và khi mình gọi function lớn là getPeople() ở viewDidLoad thì ngoài việc thực các việc bên trong, mình còn có thể thông qua closure completion này để thông báo/ làm cái gì đó (cụ thể là báo pass or fail)

Có vẻ như hơi nhiều, mình sẽ để phần tiếp theo qua bài 3.

0