RxSwift — nó là gì, tính năng và lập trình phản ứng

Tác giả: IT Sectr Đã đăng: 2026-05-03 Thời gian đọc: 10 phút

RxSwift là một thư viện lập trình phản ứng dành cho iOS, triển khai mẫu Observable và các toán tử chức năng để làm việc với luồng dữ liệu bất đồng bộ. Nó chuyển các khái niệm ReactiveX (Rx) sang ngôn ngữ Swift, cung cấp một API thống nhất để xử lý các sự kiện từ UI, yêu cầu mạng, cơ sở dữ liệu và bộ hẹn giờ. Theo ReactiveX, 2025, thư viện được sử dụng trong hơn 60.000 dự án trên GitHub và vẫn là tiêu chuẩn lập trình phản ứng cho Swift cho đến khi Combine gốc ra đời. RxSwift thay thế delegate, closure và thông báo bằng một chuỗi xử lý sự kiện duy nhất.

Những điểm chính

  • RxSwift — triển khai ReactiveX cho Swift dựa trên mẫu Observable và chuỗi toán tử
  • Observable — nguồn sự kiện bất đồng bộ có thể hoàn thành thành công, có lỗi hoặc vô hạn
  • Subject — sự kết hợp giữa Observable và Observer cho phép gửi sự kiện thủ công vào luồng
  • Schedulers kiểm soát luồng nào thực hiện đăng ký, quan sát và xử lý sự kiện
  • Toán tử map, flatMap, filter, combineLatest biến đổi và kết hợp luồng mà không có điều kiện cạnh tranh

RxSwift là gì?

RxSwift là bản port Swift của thư viện ReactiveX (Rx) do Microsoft tạo ra cho .NET vào năm 2012. Ý tưởng cốt lõi của Rx là biểu diễn bất kỳ nguồn dữ liệu bất đồng bộ nào dưới dạng chuỗi Observable mà các toán tử chức năng có thể được áp dụng. Trong phát triển iOS, RxSwift được sử dụng để liên kết các sự kiện UI (nhấn nút, nhập văn bản, cử chỉ) với logic ứng dụng mà không cần delegate rõ ràng và target-action.

Thư viện bao gồm ba mô-đun: RxSwift (lõi — Observable, Operator, Scheduler), RxCocoa (tích hợp UIKit — phần mở rộng rx cho UIButton, UITextField, UITableView) và RxRelay (Subject không có sự kiện kết thúc). Sự phân tách này cho phép sử dụng lõi trong Swift phía máy chủ và kiểm tra, chỉ kết nối trình bao bọc UI cho các ứng dụng iOS.

Theo khảo sát Stack Overflow, 2025, RxSwift nằm trong top 5 thư viện bên thứ ba được sử dụng nhiều nhất cho iOS. Lý do chính cho sự phổ biến của nó là xử lý thống nhất tất cả các mẫu bất đồng bộ: yêu cầu mạng qua URLSession, hoạt ảnh qua UIViewPropertyAnimator, thông báo qua NotificationCenter và delegate qua DelegateProxy — tất cả đều quy về một Observable với vòng đời có thể dự đoán được.

Triết lý lập trình phản ứng

Lập trình phản ứng là một mô hình trong đó chương trình phản ứng với các thay đổi dữ liệu thay vì thăm dò chúng. Thay vì viết “lấy dữ liệu → xử lý → cập nhật UI”, nhà phát triển mô tả một chuỗi biến đổi: “khi dữ liệu thay đổi, áp dụng bộ lọc, sau đó map, sau đó cập nhật UI”. RxSwift triển khai mô hình này thông qua chuỗi Observable với thực thi lười biếng — không có gì xảy ra cho đến khi có người đăng ký xuất hiện.

Các thành phần chính của RxSwift: Observable, Subject, Disposable

Observable là kiểu cơ bản của RxSwift đại diện cho một chuỗi các sự kiện theo thời gian. Observable có thể gửi ba loại sự kiện: next (giá trị mới), error (lỗi kết thúc luồng) và completed (hoàn thành thành công). Có Observable hữu hạn (hoàn thành sau khi gửi tất cả giá trị) và Observable vô hạn (ví dụ: sự kiện UI — không bao giờ hoàn thành).

Observable và vòng đời của nó

Vòng đời của Observable bao gồm ba giai đoạn: tạo (create, just, from), biến đổi (toán tử map, filter, flatMap) và đăng ký (subscribe). Không có đăng ký, Observable không thực hiện bất kỳ hành động nào — nó là một chuỗi lười biếng. Sau khi đăng ký, Observable bắt đầu gửi sự kiện cho người đăng ký cho đến khi hoàn thành hoặc người đăng ký hủy đăng ký qua Disposable.

swift
import RxSwift

// Tạo Observable từ mảng
let numbers = Observable.from([1, 2, 3, 4, 5])

// Biến đổi qua toán tử
let squared = numbers
    .filter { $0 % 2 == 0 }
    .map { $0 * $0 }

// Đăng ký với xử lý sự kiện
let disposable = squared
    .subscribe(onNext: { print($0) },
               onError: { print("Error: \($0)") },
               onCompleted: { print("Done") })

Subject là một kiểu vừa là Observable (có thể đăng ký) vừa là Observer (có thể gửi sự kiện). RxSwift cung cấp bốn loại Subject: PublishSubject (chỉ sự kiện mới), BehaviorSubject (có giá trị ban đầu), ReplaySubject (lưu đệm N sự kiện gần nhất) và AsyncSubject (chỉ giá trị cuối cùng trước khi hoàn thành). Subject hữu ích để tích hợp mã mệnh lệnh (closure, delegate) vào chuỗi phản ứng.

Disposable là mã thông báo hủy đăng ký. Khi người đăng ký không muốn nhận sự kiện nữa, nó gọi disposable.dispose(). Trong thực tế, DisposeBag được sử dụng: một tập hợp các Disposable tự động hủy tất cả đăng ký khi chủ sở hữu bị hủy khởi tạo (ví dụ: UIViewController). Điều này ngăn rò rỉ bộ nhớ không thể tránh khỏi khi quản lý đăng ký thủ công.

Loại SubjectGiá trị ban đầuGửi lại cho người đăng kýTrường hợp sử dụng
PublishSubjectKhôngChỉ sự kiện mớiSự kiện UI, thông báo hiếm
BehaviorSubjectCuối cùng + mớiTrạng thái, luồng dữ liệu
ReplaySubjectKhôngBộ đệm N + mớiLưu cache lịch sử
AsyncSubjectKhôngChỉ cuối cùngTác vụ tính toán
PublishRelayKhôngChỉ mớiKhông có error/completed

Toán tử biến đổi và lọc luồng

Toán tử trong RxSwift là các hàm nhận một Observable và trả về một Observable khác, biến đổi luồng dữ liệu. Bằng cách kết hợp các toán tử, nhà phát triển xây dựng chuỗi xử lý khai báo mà không có biến trung gian và điều kiện cạnh tranh. Tất cả toán tử đều lười biếng: chuỗi được xây dựng khi mô tả và thực thi khi đăng ký.

Toán tử biến đổi thay đổi mỗi sự kiện trong luồng. map áp dụng một hàm cho mỗi phần tử, flatMap mở Observable từ mỗi phần tử thành một luồng phẳng duy nhất, scan tích lũy kết quả trung gian (tương tự reduce nhưng phát ra mỗi bước). buffer nhóm các phần tử theo thời gian hoặc số lượng, window chia luồng thành các Observable lồng nhau theo cửa sổ.

swift
// Ví dụ chuỗi toán tử: tìm kiếm với debounce
searchTextField.rx.text
    .orEmpty
    .debounce(.milliseconds(300), scheduler: MainScheduler.instance)
    .distinctUntilChanged()
    .flatMapLatest { query -> Observable<[String]> in
        return apiService.search(query)
    }
    .bind(to: tableView.rx.items(cellIdentifier: "Cell")) { _, item, cell in
        cell.textLabel?.text = item
    }
    .disposed(by: disposeBag)

Toán tử lọc chỉ cho phép các sự kiện thỏa mãn điều kiện đi qua. filter lọc theo vị từ, distinctUntilChanged chỉ cho phép các giá trị khác với giá trị trước đó, take và takeWhile giới hạn số lượng sự kiện. skipskipWhile bỏ qua N sự kiện đầu tiên hoặc sự kiện cho đến khi một điều kiện được đáp ứng. Để xử lý lỗi, catchError (chặn và thay thế) và retry (thử lại chuỗi khi có lỗi) được sử dụng.

Toán tử kết hợp kết hợp nhiều Observable thành một. combineLatest hợp nhất các giá trị mới nhất từ nhiều luồng thành một tuple, zip ghép cặp các phần tử có cùng chỉ mục, merge kết hợp nhiều luồng thành một theo thứ tự sự kiện đến. withLatestFrom kết hợp một sự kiện từ luồng chính với giá trị mới nhất từ luồng khác — hữu ích cho sự kiện UI với trạng thái hiện tại.

Danh mụcToán tửMô tả
Biến đổimapBiến đổi mỗi giá trị qua một hàm
Biến đổiflatMapMở Observable lồng nhau thành luồng phẳng
LọcfilterCho phép giá trị theo vị từ
LọcdistinctUntilChangedChỉ cho phép giá trị đã thay đổi
Kết hợpcombineLatestKết hợp giá trị mới nhất từ 2+ luồng
Kết hợpzipGhép cặp phần tử theo chỉ mục
Điều khiểndebounceTrì hoãn sự kiện cho đến khi luồng tạm dừng
Điều khiểntakeLấy N sự kiện đầu tiên và kết thúc luồng

Schedulers và quản lý luồng thực thi

Scheduler trong RxSwift là một sự trừu tượng hóa trên luồng thực thi (hoặc hàng đợi). Scheduler xác định luồng nào thực hiện việc tạo sự kiện, biến đổi và đăng ký. Không giống như GCD, nơi nhà phát triển chỉ định rõ ràng DispatchQueue, RxSwift sử dụng hai tham số: subscribeOn (luồng nào thực thi Observable) và observeOn (luồng nào gọi người đăng ký).

MainScheduler và BackgroundScheduler

MainScheduler thực thi mã trên luồng chính — bắt buộc để cập nhật UIKit (tất cả thay đổi UI phải xảy ra trên luồng chính). SerialDispatchQueueScheduler bao bọc một hàng đợi GCD nối tiếp, ConcurrentDispatchQueueScheduler bao bọc một hàng đợi đồng thời. Cho các tác vụ nền, ConcurrentDispatchQueueScheduler với qos: .background hoặc .utility được sử dụng.

swift
// Mẫu điển hình: công việc nền + UI trên main
apiService.fetchData()
    .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { data in
        self.tableView.reloadData()
        self.loadingIndicator.stopAnimating()
    })
    .disposed(by: disposeBag)

Sử dụng Scheduler đúng cách ngăn chặn chặn UI trong các yêu cầu mạng và tính toán nặng. subscribeOn ảnh hưởng đến toàn bộ thượng nguồn (tất cả toán tử trước observeOn thực thi trên bộ lập lịch được chỉ định). observeOn chuyển hạ nguồn — tất cả toán tử sau observeOn thực thi trên bộ lập lịch được chỉ định. Một chuỗi có thể có nhiều observeOn để chuyển đổi giữa các luồng ở các giai đoạn biến đổi khác nhau.

SerialDispatchQueueScheduler đảm bảo xử lý sự kiện tuần tự, điều quan trọng cho an toàn luồng của tài nguyên chia sẻ. Cho các hoạt động tải cao (xử lý hình ảnh, phân tích JSON), hãy sử dụng ConcurrentDispatchQueueScheduler — RxSwift sẽ giữ thứ tự sự kiện trong một Observable, nhưng các Observable khác nhau có thể được xử lý song song.

Ứng dụng thực tế của RxSwift trong iOS

RxSwift trong các dự án iOS thường được sử dụng để liên kết UI với dữ liệu thông qua chuỗi phản ứng. RxCocoa cung cấp phần mở rộng rx cho tất cả thành phần UIKit tiêu chuẩn: rx.tap cho UIButton, rx.text cho UITextField, rx.selectedRow cho UIPickerView. Điều này cho phép từ bỏ @IBAction và delegate, thay thế chúng bằng đăng ký khai báo.

RxSwift với MVVM

MVVM (Model-View-ViewModel) là một mẫu kiến trúc trong đó ViewModel quản lý trạng thái và logic nghiệp vụ, và View đăng ký các thuộc tính phản ứng của ViewModel. RxSwift phù hợp hoàn hảo với MVVM: ViewModel xuất bản Observable hoặc Driver cho dữ liệu, View đăng ký chúng qua bind. ViewModel không có tham chiếu đến View — nó trả về Observable mà View tiêu thụ.

swift
class LoginViewModel {
    let email = BehaviorRelay<String>(value: "")
    let password = BehaviorRelay<String>(value: "")

    var isFormValid: Observable<Bool> {
        return Observable
            .combineLatest(email, password) {
                !$0.isEmpty && $0.contains("@") && $1.count >= 6
            }
    }
}

// Trong ViewController:
viewModel.isFormValid
    .bind(to: loginButton.rx.isEnabled)
    .disposed(by: disposeBag)

Yêu cầu mạng là trường hợp sử dụng phổ biến thứ hai của RxSwift. URLSession.rx.response bao bọc một yêu cầu HTTP thành Observable trả về (response, data) khi thành công hoặc error khi thất bại. Kết hợp với Codable và toán tử map, ta có một lớp API phản ứng nhỏ gọn: Observable<MyModel> không cần callback và xử lý lỗi trong mỗi phương thức. Khi lỗi mạng, toán tử retry(3) tự động thử lại yêu cầu ba lần với backoff theo cấp số nhân.

RxSwift vs Combine

Combine là framework gốc của Apple được giới thiệu trong iOS 13. Nó giải quyết các tác vụ giống như RxSwift: làm việc với sự kiện bất đồng bộ qua Publisher, Subscriber và toán tử. Tuy nhiên, Combine có những khác biệt chính: kiểu lỗi nghiêm ngặt qua kiểu Failure, hỗ trợ Swift Concurrency tích hợp (async/await) và tích hợp với SwiftUI qua @Published và ObservableObject.

RxSwift thắng về tương thích ngược — nó hỗ trợ iOS 8+, trong khi Combine yêu cầu iOS 13+. RxSwift có hệ sinh thái phong phú hơn các phần mở rộng bên thứ ba (RxDataSources, RxGesture, RxAnimated) và tài liệu toán tử chi tiết. Cho các dự án hỗ trợ phiên bản iOS cũ, RxSwift vẫn là lựa chọn duy nhất.

Cho các dự án mới với iOS 13+, Apple khuyến nghị Combine. Nó được tích hợp chặt chẽ với SwiftUI, có kích thước nhị phân nhỏ hơn và hỗ trợ chính thức. Tuy nhiên, di chuyển mã RxSwift hiện có sang Combine yêu cầu viết lại tất cả Observable → Publisher, và hệ sinh thái RxCocoa không có tương đương Combine đầy đủ — UIKit không có Publisher gốc cho tất cả thành phần UI.

Đặc điểmRxSwiftCombine
iOS tối thiểuiOS 8+iOS 13+
Loại lỗiError (bất kỳ)Generic Failure
Mở rộng UIRxCocoa (UIKit, AppKit)@Published (SwiftUI)
Toán tử400+ toán tử~100 toán tử
Swift ConcurrencyQua cầu nốiHỗ trợ gốc
Trạng tháiBên thứ baApple chính thức

Câu hỏi thường gặp

Sự khác biệt giữa Observable và Subject trong RxSwift là gì?

Observable là nguồn sự kiện với thực thi lười biếng. Subject vừa là Observable vừa là Observer — bạn có thể đăng ký nó và gửi sự kiện mới thủ công. Subject hữu ích để tích hợp mã mệnh lệnh vào chuỗi phản ứng.

Khi nào nên sử dụng RxSwift thay vì Combine?

RxSwift được chọn khi cần hỗ trợ iOS 11-12, có cơ sở mã RxSwift hiện tại hoặc cần hệ sinh thái toán tử phong phú (400+ so với ~100 trong Combine). Cho các dự án mới trên iOS 13+, Combine được ưu tiên.

DisposeBag là gì và tại sao cần nó?

DisposeBag là một tập hợp các mã thông báo Disposable tự động hủy tất cả đăng ký khi chủ sở hữu bị hủy khởi tạo. Nếu không có DisposeBag, đăng ký tạo tham chiếu mạnh đến closure, dẫn đến rò rỉ bộ nhớ khi UIViewController bị hủy.

Làm thế nào để xử lý lỗi trong RxSwift?

Sử dụng catchError để thay thế lỗi bằng giá trị mặc định, retry để thử lại thực thi Observable, materialize để biến lỗi thành sự kiện. Trong lớp UI, Driver và Signal không truyền lỗi — chúng được xử lý nội bộ.

Driver khác Observable trong RxCocoa như thế nào?

Driver là một loại Observable đặc biệt đảm bảo thực thi trên MainScheduler, không có lỗi và chia sẻ tài nguyên. Driver đảm bảo cập nhật UI xảy ra trên luồng chính. Observable không cung cấp bảo đảm như vậy — cần observeOn.

Tổng kết

  • RxSwift là thư viện lập trình phản ứng cho iOS triển khai mẫu Observable và 400+ toán tử biến đổi
  • Observable, Subject, Disposable là ba kiểu cơ bản tạo nền tảng cho tất cả chuỗi phản ứng
  • Toán tử map, flatMap, filter, combineLatest, debounce cho phép xây dựng chuỗi khai báo không có điều kiện cạnh tranh
  • Schedulers (subscribeOn / observeOn) quản lý luồng thực thi, ngăn chặn chặn UI
  • RxCocoa cung cấp phần mở rộng rx cho UIKit, thay thế delegate và target-action bằng đăng ký phản ứng
  • Combine là giải pháp thay thế gốc của Apple cho iOS 13+, nhưng RxSwift vẫn phù hợp cho phiên bản cũ

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm