Contents
Chào bạn đến với Fx Studio. Chúng ta tiếp tục với series RxSwift, phần tiếp theo là Observables. Trong các phần trước, bạn đã cài đặt và Hello world
thành công với RxSwift rồi. Còn nếu bạn chưa đọc qua thì có thể ghé sang link sau đây:
Còn nếu như mọi thứ đã ổn rồi thì …
Bắt đầu thôi!
Chuẩn bị
- Xcode 11
- Swift 5
- Playground
Lần này, chúng ta vẫn sử dụng Playground cho việc code demo phần lý thuyết. Cũng chưa có gì liên quan tới việc tạo giao diện trong phần này và vài phần sau. Do đó, bạn hãy thoái mái vui chơi cùng Playground. Nếu bạn quên link checkout source code thì có thể checkout tại đây.
1. Observables – Trái tim của RxSwift
Đây là phần trung tâm của RxSwift. Observable chính là trái tim của cả hệ thống. Nó là nơi mà các thành phần khác có thể quan sát được. Nó tác động trực tiếp tới giao diện của bạn, dựa vào những gì mà nó phát ra cho bạn.
Everything is a sequence.
Đó là một câu nỗi tiếng mà bất cứ đồng chí nào lao đầu vào học Rx thì đều cũng bắt gặp ngay. Nhưng đó cũng chính là nơi hầu hết mọi người đều gục ngã. Tại sao như vậy?
1.1. Khái niệm
Khi tìm hiểu về RxSwift hay Rx nói chung, bạn sẽ nghe tới các khái niệm observable
, observable sequence
hay đơn giản là sequence
. Khá là mơ hồ nhưng tất cả chúng đều là một và ám chỉ tới nguồn phát
. Khác nhau ở góc độ mà họ muốn mình hiểu.
- Observable : là nguồn phát ra dữ liệu mà các đối tượng khác có thể quan sát được và đăng ký tới được.
- Sequence : là luồng dữ liệu được nguồn phát phát đi. Vấn đề quan trọng, bạn cần hiểu nó như 1 Array, nhưng chúng ta không thể lấy hết 1 lúc tất cả các giá trị của nó. Và chúng ta không biết nó lúc nào kết thúc hay lúc nào lỗi …
Để tăng thêm độ hack não, một số cha dev còn sinh thêm từ khoá Stream
. Trong trường hợp này, bạn hãy hết sức bình tĩnh. Vì Stream cũng được xem là một Sequence mà thôi, quá ez!
Và tất nhiên, nó cũng là luồng hay thread đó. Bạn xem chúng như là một dòng chảy dữ liệu mà ta quan sát được từ nguồn phát.
1.2. Marble Diagrams
Và người ta tránh đi việc nhầm lẫn & khó hiểu, thì sử dụng marble diagrams
để mô tả sự hoạt động của nguồn phát. Bạn vào trang này để xem https://rxmarbles.com/.
Ví dụ cho một toán tử được mô tả bằng Marble Diagrams. Bạn có thể kéo tả các ô tròn tròn đó qua lại với nhau. Và kết quả nó sẽ ảnh hưởng ở dưới.
Với 1 biểu đồ thì bao gồm như sau:
- Bắt đầu từ trái sang phải
- Các giá trị phát ra là các số được vòng tròn & tô màu lại
- Dấu
|
biểu tượng cho kết thúc (completed) - Dấu
X
biểu tượng cho lỗi (error)
2. Vòng đời Observables
2.1. Asynchronous data streams
Tạm dừng một chút, khi ta quay lại một trong những định nghĩa lớn cho RxSwift hay cho toàn bộ Reactive Programming như sau:
Reactive programming is programming with asynchronous data streams.
Và bạn nên tập trung vào luồng dữ liệu bất đồng bộ. Nó không phải là kiểu lập trình hay xử lý đa luồng. Chính xác đây được hiểu là thời điểm mà dữ liệu trong luồng được phát đi. Nó không đồng bộ với nhau và cũng không xác định theo một thời gian cụ thể nào đó.
Cuối cùng, nó không chỉ là dữ liệu. Bạn nên hiểu nó ở mức độ tương đối. Vì đôi khi, kiểu dữ liệu của bạn sẽ là các sự kiện hoặc là một nguồn phát.
2.2. Observables life cycle
Cuộc đời của một Observable rất chi là đơn giản. Nó chỉ có một nhiệm vụ là bắn
những gì mà nó có đi thôi. Nên cuộc đời nó sẽ xoay quanh giá trị và nó bắn đi. Với 3 kiểu giá trị mà 1 Observable được phép bắn đi như sau:
- Value : chính là giá trị dữ liệu nguồn phát phát đi (hay còn gọi là
emit
). - Error: là lỗi khi có gì đó sai sai trong quá trình hoạt động. Sau đó nó cũng tự kết thúc.
- Completed: kết thúc cuộc đời.
Thông qua 3 giá trị đó thì mô tả cuộc đời Observable như sau:
- Khởi tạo Observable
- Cứ
onNext
là sẽ phát giá trị đi - Quá trình này cứ lặp đi lặp lại cho tới khi
- Hết thì sẽ là
completed
- Lỗi thì sẽ là
error
- Hết thì sẽ là
- Khi khi đã
completed
hoặcerror
thì Observable không thể phát ra được gì nữa –> kết thúc
Qua trên, bạn cũng hiểu được sơ sơ rồi. Chúng ta sang phần demo code thì sẽ hiểu kĩ hơn nữa. Code là ngôn ngữ tốt nhất mà các dev sử dụng. Ahihi!
3. Cách tạo Observables
Đây chỉ là những cách đơn giản mà thôi, phần khó nâng cao sẽ ở các bài viết sau. Nhưng bạn cũng cần phải nắm được kiến thức cơ bản này.
Tạo các Observables thông qua việc thực thi các toán tử sau just
, of
và from
. Kiểu dữ liệu của Observable là Observable
. Để dể hiểu hơn bạn hãy tạo 1 Playground từ project của bài trước và thêm đoạn code setup sau.
let iOS = 1
let android = 2
let flutter = 3
3.1. just
Ba biến trên thì khá đơn giản & với kiểu dữ liệu là Int
. Tiếp theo bạn khai báo một Observable nào:
let observable1 = Observable<Int>.just(iOS)
Trong đó:
observable1
là biến kiểu Observable<Int>
chính là kiểu dữ liệu choOutput
của Observablejust
là toán tử để tạo ra 1 observable sequence với 1 phần tử duy nhất
Tại sao là just
? Thì cái tên này cũng nói lên tất cả rồi. Nó sẽ tạo ra 1 Observable và phát đi 1 giá trị duy nhất. Sau đó, nó sẽ kết thúc.
3.2. of
Tiếp tục, công việc vui vẻ là tạo thêm các Observables nào. Bạn thêm dòng code này vào.
let observable2 = Observable.of(iOS, android, flutter)
Trong đó:
- Ta thấy đối tượng Observable lần này sử dụng toán tử
of
- Không cần khai báo kiểu dữ liệu cho Output
- Thư viện tự động nội suy ra kiểu dữ liệu từ các dữ liệu cung cấp trong
of(.....)
Theo ví dụ trên, kiểu dữ liệu của observable2
là Observable<Int>
. Để hiểu kĩ hơn, ta biến tấu nó thêm một chút nữa. Bạn xem đoạn code sau:
let observable3 = Observable.of([iOS, android, flutter])
Cũng vẫn là of
, nhưng kiểu dữ liệu cho observable3
lúc này là Observable<[Int]>
. Nó khác cái trên ở chỗ kiểu cho mỗi giá trị phát ra là 1 Array Int, chứ không phải Int riêng lẻ. Nó cũng khá nhập nhèn dữ liệu ở đây.
3.3. from
Chúng ta tiếp tục thêm dòng code sau Playground của bạn.
let observable4 = Observable.from([iOS, android, flutter])
Lần này, sử dụng toán tử from
, tham số cần truyền vào là 1 array. Và kiểu dữ liệu cho biến observalbe4
là Observable<Int>
. Cách này giúp bạn đỡ phải of
nhiều phần tử. Xem hình mô tả ở dưới để thấy trực quan hơn.
Vâng, bạn đã có trong tay 3 vũ khí đầu tiên để tạo ra một Observable
rồi. Giờ sang phần tiếp theo nào …
4. Subscribing to Observables
4.1. addObserver
Có được nguồn phát rồi, công việc hiện tại là lắng nghe nó thôi. Mình chắc là bạn cũng đã ít nhiều lần code với KVO trong iOS rồi. Đó là hình thức sơ khai cho mô hình (Reactive Programming) này. Đây là ví dụ cho việc lắng nghe từ sự kiện của bàn phím.
let observer = NotificationCenter.default.addObserver( forName: UIResponder.keyboardDidChangeFrameNotification, object: nil,
queue: nil) { notification in
// Handle receiving notification
}
RxSwift cũng tương tự vậy thôi. Trong UIKit hay các thư viện được build sẵn trong OS của Apple, các singleton cũng có khả năng phát đi được dữ liệu. Đó chính là thuyết âm mưu mà Apple đã âm thầm cài đặt lâu nay.
Với RxSwift, bạn có thể xem các dữ liệu mà Observable phát ra. Nó cũng là 1 sequence trình tự lần lượt phát đi các phần tử. Nó tương đương với hàm onNext
của Observable. Đoạn code sau mô tả cho việc phát đi lần lượt các giá trị.
let sequence = 0..<3
var iterator = sequence.makeIterator()
while let n = iterator.next() {
print(n)
}
Bây giờ, hầu như các ngôn ngữ lập trình đều tiệm cận lại với nhau rồi.
4.2. Subscribe
Hiển nhiên, RxSwift không chỉ có vậy. Chúng ta có thể lắng nghe nhiều hơn 1 cái onNext
kia. Nó tương ứng với từng kiểu giá trị nhận được (3 kiểu mà Observable có thể phát ra). Công việc này được gọi là .subscribe
.
Ta sẽ tiếp tục với các observable
được tạo trên kia. Bắt đầu với việc lắng nghe đơn giản nhất.
observable1.subscribe { event in print(event) }
Dùng biến observable
và gọi toán tử .subscribe
. Để handle dữ liệu nhận được, chúng ta cung cấp cho nó 1 closure
. Trong closure, chỉ có in giá trị ra thôi. Kết quả như sau:
next(1) completed
Tuy nhiên, có cái chữ next
& completed
cũng khó chịu. Muốn lấy được giá trị trong chữ đó, bạn phải biến tấu thêm 1 xí nữa.
observable2.subscribe { event in
if let element = event.element {
print(element)
}
}
Kết quả cho việc lăng nghe tới observable2
mượt hơn rồi.
1
2
3
4.3. Handle events
Tiếp theo, nếu bạn cần lấy thêm các sự kiện error
hay completed
thì lại biến tấu tiếp.
- Dành cho
onNext
observable3.subscribe(onNext: { element in
print(element)
})
- Full options
observable4.subscribe(onNext: { (value) in
print(value)
}, onError: { (error) in
print(error.localizedDescription)
}, onCompleted: {
print("Completed")
}) {
print("Disposed")
}
Về Disposed
thì mình sẽ đề cập ở các phần sau nha. Bạn hãy thực thi các đoạn code trên và cảm nhận kết quả nhoé!
Với các Full options
thì bạn bắt được hết các kiểu event với đầy đủ 3 kiểu giá trị mà Observable có thể phát ra. Đối với mỗi loại, bạn xử lý bằng việc phải cung cấp một closure
cho nó. Và bạn có thể bỏ bớt đi các handle không cần thiết.
Như chỉ quan tâm tới onNext
và onCompleted
thôi. Thì như đoạn code sau:
observable4.subscribe(onNext: { (value) in
print(value)
}, onCompleted: {
print("Completed")
})
Tới đây, bạn có thể thoải mái tung hoành ngang dọc với Observable rồi đó. Chúng ta qua phần tiếp theo nào!
5. Các dạng đặc biệt của Observables
Đây là các loại Observables đặc biệt và bạn có thể tạo nhanh chúng từ các toán tử (operators – phần này sẽ trình bày sau). Mỗi loại sẽ có một số đặc điểm riêng.
5.1. Empty
Đây là toán tử mà nó tạo ra 1 Observable. Observable này đặc biệt là không phát ra phần tử nào hết và nó sẽ kết thúc ngay. Demo code như sau:
let observable = Observable<Void>.empty() observable.subscribe( onNext: { element in print(element) }, onCompleted: { print("Completed") } )
Chạy đoạn code trên và cảm nhận kết quả nào.
5.2. Never
Tiếp theo, cũng là một toán tử đặc biệt. Nó cũng tạo ra 1 Observable như trên
let observable = Observable<Any>.never() observable.subscribe( onNext: { element in print(element) }, onCompleted: { print("Completed") } )
Bạn cũng thực thi đoạn code trên, bạn sẽ thấy hoàn toàn im lìm. Không có gì ở đây được phát và được nhận hết.
Toán tử
.empty
nó khác với.never
nha. Never thì sẽ không phát ra gì cả và cũng không kết thúc luôn.
5.3. Range
Qua em cuối nào. Cũng tạo ra 1 Observable và lần này sẽ có dữ liệu phát ra.
Ta có demo code đơn giản như sau:
let observable = Observable<Int>.range(start: 1, count: 10) var sum = 0 observable .subscribe( onNext: { i in sum += i } , onCompleted: { print("Sum = \(sum)") } )
Nó giống như một vòng for
đơn giản. Observable với kiểu phần tử được phát đi là Int
. Chúng sẽ phát ra lần lượt, số lần phát chính là count
và giá trị bắt đầu phát ra là start
. Sau mỗi lần phát thì start
sẽ được tăng lên 1 đơn vị.
Toán tử này cho mỗi
Int
thôi. Chưa có điều kiện tìm hết và test hết các kiểu dữ liệu khác.
Tạm thời thì mình xin kết thúc bài viết về sơ lược Observables trong RxSwift. Tất nhiên, để bàn về Observables thì còn rất nhiều. Các phần hay sẽ còn ở phía sau. Nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.
À, quan trọng nhất là nếu bạn thắc mắc: “Tại sao tụi Observables trên cứ in & ra 1 lèo hết tất cả như vậy?”
Hiện tại, chúng ta vẫn tương tác trên code đồng bộ và luồng dữ liệu đồng bộ. Nên chúng nó cứ chạy 1 lèo như rứa. Tới phần UIKit thì mọi thứ sẽ khác bọt đi nhiều.
Tạm kết
- Observables là nguồn phát dữ liệu
- Sequence, Observable Sequence hay Stream đều mang ý nghĩa giống nhau
- Có 3 cách tạo 1 Observables đơn giản
just
phát ra phần tử duy nhất và kết thúcof
phát ra lần lượt các phần tử cung cấp và kết thúcfrom
tương tự nhưof
mà tham số truyền vào là 1 array, tiết kiệm thời gian ngồi gõ code
- Các observable đặc biết xí
empty
không có gì hết và kết thúcnever
không có gì luôn và không kết thúc luônrange
tạo ra 1 vòng for nhỏ nhỏ, dùng choInt
và mỗi lần như vậy thì sẽ tăng giá trị lên
Okay! Tới đây, mình xin kết thúc bài viết về Observables trong RxSwift. Và nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.
- Bài viết tiếp theo tại đây.
Cảm ơn bạn đã đọc bài viết này!
Related Posts:
Written by chuotfx
Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!
Leave a Reply Cancel reply
Fan page
Tags
Recent Posts
- Charles Proxy – Phần 1 : Giới thiệu, cài đặt và cấu hình
- Complete Concurrency với Swift 6
- 300 Bài code thiếu nhi bằng Python – Ebook
- Builder Pattern trong 10 phút
- Observer Pattern trong 10 phút
- Memento Pattern trong 10 phút
- Strategy Pattern trong 10 phút
- Automatic Reference Counting (ARC) trong 10 phút
- Autoresizing Masks trong 10 phút
- Regular Expression (Regex) trong Swift
You may also like:
Archives
- September 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (4)
- April 2024 (2)
- March 2024 (5)
- January 2024 (4)
- February 2023 (1)
- January 2023 (2)
- November 2022 (2)
- October 2022 (1)
- September 2022 (5)
- August 2022 (6)
- July 2022 (7)
- June 2022 (8)
- May 2022 (5)
- April 2022 (1)
- March 2022 (3)
- February 2022 (5)
- January 2022 (4)
- December 2021 (6)
- November 2021 (8)
- October 2021 (8)
- September 2021 (8)
- August 2021 (8)
- July 2021 (9)
- June 2021 (8)
- May 2021 (7)
- April 2021 (11)
- March 2021 (12)
- February 2021 (3)
- January 2021 (3)
- December 2020 (3)
- November 2020 (9)
- October 2020 (7)
- September 2020 (17)
- August 2020 (1)
- July 2020 (3)
- June 2020 (1)
- May 2020 (2)
- April 2020 (3)
- March 2020 (20)
- February 2020 (5)
- January 2020 (2)
- December 2019 (12)
- November 2019 (12)
- October 2019 (19)
- September 2019 (17)
- August 2019 (10)