RxSwift: KVO – Key Value Observing

I. Khái niệm: Key Value Observing hay còn được gọi là KVO là một cơ chế cho phép một Object có thể nghe sự thay đổi của thuộc tính nằm trong đối tượng khác. KVO đặc biệt hữu dụng trong việc kết nối giữa model layer và controller layer (ví dụ như trong mô hình

I. Khái niệm:

  • Key Value Observing hay còn được gọi là KVO là một cơ chế cho phép một Object có thể nghe sự thay đổi của thuộc tính nằm trong đối tượng khác.
  • KVO đặc biệt hữu dụng trong việc kết nối giữa model layer và controller layer (ví dụ như trong mô hình MVC). Controller object sẽ lắng nghe sự thay đổi của Model layer và View layer sẽ lắng nghe sự thay đổi của Controller layer.
  • Một object có thể có một hoặc nhiều object khác cùng lắng nghe sự thay đổi của nó; và ngược lại thì một object cũng có thể lắng nghe sự thay đổi của một hoặc nhiều object khác.

II. KVO trong iOS:

Để hiểu rõ hơn về KVO trong iOS thì chúng ta sẽ cùng xem ví dụ sau:

Khởi tạo Object Player với một property là point.

classPlayer:NSObject{@objcdynamicvar point =0funcincreasePoint(){
        point = point +1}}

Để có thể sử dụng KVO với class Player thì Player bắt buộc phải là subclass của NSObject. Để các Object khác có thể lắng nghe sự thay đổi của property point thì property này cần phải được gắn anotation@objc dynamic.

Khởi tạo một object player, khi đó object player này sẽ đóng vai trò là Observable.

classViewController:UIViewController{let player =Player()overridefuncviewDidLoad(){super.viewDidLoad()}}

Thực hiện subscribe để lắng nghe sự thay đổi value của property point bên trong object player.

classViewController:UIViewController{let player =Player()overridefuncviewDidLoad(){super.viewDidLoad()
        
        player.observe(Player.point, options:[.old,.new], changeHandler:{ object, change inprint("LOG + object: (object)")print("LOG + newValue: (change.newValue), oldValue: (change.oldValue)")})}}

function observe() nhận vào các parameters với ý nghĩa như sau:

  • Player.point: path dẫn tới observable property, hiểu một cách đơn giản là đường dẫn tới property có thể lắng nghe sự thay đổi bên trong Observable class.
  • options: option nhận dữ liệu khi value của property thay đổi, như trong example là có nghĩa là sẽ lấy cả giá trị cũ và giá trị mới mỗi khi property point được cập nhật giá trị.
  • changeHandler: callback được gọi tới khi property point cập nhật giá trị, callback này sẽ trả về 2 params là object tương ứng với đối tượng đang được lắng nghe property (trong ví dụ là object player) và change là object mang theo value của property point khi nó được thay đổi giá trị.

Tạo button và thực hiện việc update giá trị của property point mỗi khi click.

@IBActionfunchandleButton(_ sender:UIButton){
    player.increasePoint()}

Chúng ta có thể quan sát console log và thấy được kết quả được in ra mỗi lần click button

LOG+ object:<DemoKVO.Player:0x600001818290>LOG+ newValue:Optional(1), oldValue:Optional(0)LOG+ object:<DemoKVO.Player:0x600001818290>LOG+ newValue:Optional(2), oldValue:Optional(1)LOG+ object:<DemoKVO.Player:0x600001818290>LOG+ newValue:Optional(3), oldValue:Optional(2)

III. KVO với RxSwift:

Với RxSwift, chúng ta có thể thực hiện KVO với cú pháp ngắn gọn và dễ dàng hơn, cụ thể như sau:

var disposeBag =DisposeBag()// Solution 1
player.rx.observe(Player.point).subscribe(onNext:{ point inprint("LOG + point: (point)")}).disposed(by: disposeBag)// Solution 2
 player.rx.observe(Int.self,#keyPath(Player.point)).subscribe(onNext:{ point inguardlet point = point else{return}print("LOG + point with value type: (point)")}).disposed(by: disposeBag)
  • Với Solution 1 thì chúng ta chỉ cần truyền đường dẫn tới property là có thể nhận được value mỗi khi giá trị của property thay đổi.
  • Với Solution 2 thì chúng sẽ truyền thêm kiểu dữ liệu của property mà chúng ta muốn lắng nghe sự thay đổi của nó. Value nhận được là sẽ một optional chứa dữ liệu.

IV. Ứng dụng:

Chúng ta có thể ứng dụng KVO với cái UI Component của UIKit, WebKit,…. trong iOS

let webView =WKWebView()
webView.rx.observe(URL.self,#keyPath(WKWebView.url)).subscribe(onNext:{ url inprint("LOG + url: (url)")}).disposed(by: disponseBag)
let tableView =UITableView()
tableView.rx.observe(CGSize.self,#keyPath(UITableView.contentSize)).subscribe(onNext:{ contentSize inprint("LOG + contentSize: (contentSize)")}).disposed(by: disponseBag)

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ