- vừa được xem lúc

RxSwift: KVO - Key Value Observing

0 0 37

Người đăng: Trịnh Giang Đông

Theo Viblo Asia

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.

class Player: NSObject { @objc dynamic var point = 0 func increasePoint() { 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.

class ViewController: UIViewController { let player = Player() override func viewDidLoad() { super.viewDidLoad() }
}

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

class ViewController: UIViewController { let player = Player() override func viewDidLoad() { super.viewDidLoad() player.observe(\Player.point, options: [.old, .new], changeHandler: { object, change in print("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.

@IBAction func handleButton(_ 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 in print("LOG + point: \(point)") }) .disposed(by: disposeBag) // Solution 2 player.rx.observe(Int.self, #keyPath(Player.point)) .subscribe(onNext: { point in guard let 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 in print("LOG + url: \(url)") }) .disposed(by: disponseBag)
let tableView = UITableView()
tableView.rx.observe(CGSize.self, #keyPath(UITableView.contentSize)) .subscribe(onNext: { contentSize in print("LOG + contentSize: \(contentSize)") }) .disposed(by: disponseBag)

Bình luận

Bài viết tương tự

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 1: Làm quen cô nàng Flutter

Lời mở đầu. Gần đây, Flutter nổi lên và được Google PR như một xu thế của lập trình di động vậy.

0 0 254

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 3: Lột trần cô nàng Flutter, BuildContext là gì?

Lời mở đầu. Màn làm quen cô nàng FLutter ở Phần 1 đã gieo rắc vào đầu chúng ta quá nhiều điều bí ẩn về nàng Flutter.

0 0 189

- vừa được xem lúc

Swift: Tạo custom phép toán tử (Operator) của riêng bạn!

Swift cho phép bạn tạo các toán tử có thể tùy chỉnh của riêng bạn. Điều này đặc biệt hữu ích khi bạn xử lý các loại dữ liệu của riêng mình. Operator Types in Swift. Có năm loại toán tử chính trong Swift.

0 0 45

- vừa được xem lúc

Chương 6 Protocol oriented programming.

Cuốn sách này là về lập trình hướng protocol. Khi Apple thông báo swift 2 ở WWDC 2015.

0 0 28

- vừa được xem lúc

Ví dụ về UIActivityViewController

Trên iOS, UIActivityViewController cung cấp giao diện thống nhất để người dùng chia sẻ và thực hiện các hành động trên văn bản, hình ảnh, URL và các mục khác trong ứng dụng. let string = "Hello, world!". let url = URL(string: "https://nshipster.com").

0 0 45

- vừa được xem lúc

Quản lý self và cancellable trong Combine.

. . Công việc quản lý bộ nhớ memory management thường trở nên phức tạp khi chúng ta thực hiện các tác vụ bất đồng bộ asynchronous vì chúng ta thường phải lưu giữ một số object nằm ngoài scope mà object được define trong khi vẫn phải đảm bảo được việc giải phóng object đó được thực hiện đúng quy trìn

0 0 28