RxSwift — khái niệm, nguyên lý chính và lập trình phản ứng

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

RxSwift là một thư viện lập trình phản ứng cho Swift, triển khai mẫu Observable. Theo ReactiveX, 2025, đây là triển khai phổ biến nhất của Reactive Extensions cho hệ sinh thái Apple. Observable đóng vai trò là nguồn sự kiện, trong khi Observer đăng ký nhận các sự kiện đó.

Những điểm chính

  • RxSwift — triển khai Reactive Extensions cho Swift với hỗ trợ Observable, Subject và hơn 300 toán tử
  • Observable — nguồn sự kiện phát ra giá trị, lỗi hoặc tín hiệu hoàn thành
  • Subject — đồng thời là Observable và Observer, cho phép chèn sự kiện thủ công vào luồng
  • DisposeBag — cơ chế quản lý bộ nhớ tự động, hủy đăng ký khi giải phóng bộ nhớ
  • Schedulers — quản lý luồng thực thi, cho phép chuyển đổi giữa hàng đợi chính và nền

RxSwift là gì?

RxSwift là một thư viện lập trình phản ứng cho ngôn ngữ Swift, được chuyển từ Reactive Extensions (Rx). Nó cho phép mô tả các chương trình bất đồng bộ và hướng sự kiện thông qua Observable Sequence — một chuỗi dữ liệu có sẵn theo thời gian. Các nhà phát triển iOS sử dụng RxSwift để xử lý các yêu cầu mạng, sự kiện UI và dữ liệu truyền trực tuyến mà không cần callback lồng nhau.

Observable và Observer

Nền tảng của RxSwift bao gồm hai giao thức chính: ObservableType — một nguồn sự kiện có thể phát ra ba loại tín hiệu: .next(value), .error(error) và .completed. Observer đăng ký Observable thông qua phương thức subscribe và nhận các sự kiện này. Mô hình này được gọi là Reactive Streams và đảm bảo không có sự kiện nào bị mất khi đăng ký đúng cách.

Toán tử biến đổi

RxSwift cung cấp hơn 300 toán tử để làm việc với luồng: map biến đổi mỗi sự kiện, filter chỉ cho phép các sự kiện phù hợp đi qua, flatMap mở rộng các Observable lồng nhau thành một luồng duy nhất. Các toán tử được kết nối thành chuỗi, tạo ra một đường ống xử lý dữ liệu khai báo mà không có tác dụng phụ.

Traits: Single, Completable, Maybe

Ngoài Observable cơ bản, RxSwift cung cấp các kiểu bao bọc chuyên dụng. Single phát ra chính xác một giá trị hoặc lỗi — lý tưởng cho các yêu cầu HTTP. Completable hoàn thành thành công hoặc thất bại mà không có giá trị — cho các thao tác ghi. Maybe kết hợp cả hai kịch bản: có thể hoàn thành có giá trị, không có giá trị hoặc có lỗi. Các Traits này đơn giản hóa ngữ nghĩa và làm cho mã tự ghi chép.

Lập trình phản ứng trong RxSwift hoạt động như thế nào

Lập trình phản ứng trong RxSwift được xây dựng trên mẫu Observer. ObservableSequence tương tự như Sequence từ thư viện chuẩn, nhưng với truy cập bất đồng bộ đến các phần tử. Luồng sự kiện được truyền qua một chuỗi các toán tử, mỗi toán tử trả về một ObservableSequence mới mà không làm thay đổi chuỗi gốc.

Chuỗi toán tử

Các toán tử trong RxSwift là các hàm thuần túy nhận một ObservableSequence và trả về một ObservableSequence mới. Ví dụ, map tạo một chuỗi mới bằng cách áp dụng biến đổi cho mỗi phần tử. Bằng cách kết hợp các toán tử, nhà phát triển xây dựng một đường ống nơi dữ liệu đi qua tất cả các giai đoạn xử lý mà không cần biến trung gian.

Schedulers và luồng thực thi

Schedulers là một lớp trừu tượng trên các luồng thực thi trong RxSwift. Scheduler xác định luồng nào sẽ thực thi mã: MainScheduler — luồng UI, SerialDispatchQueueScheduler — hàng đợi nền. Các toán tử subscribeOn và observeOn chỉ định nơi công việc được thực hiện và nơi kết quả được xử lý, tương ứng.

Các thành phần chính của RxSwift

RxSwift bao gồm một số kiểu cơ bản, mỗi kiểu giải quyết nhiệm vụ riêng trong đường ống phản ứng. Single là Observable phát ra chính xác một giá trị hoặc lỗi, thuận tiện cho các yêu cầu mạng. Completable hoàn thành thành công hoặc thất bại mà không có giá trị. Maybe kết hợp các thuộc tính của Single và Completable.

Subject và Relay

Subject là một Observable nóng đồng thời hoạt động như Observer. PublishSubject chỉ phát ra các sự kiện mới cho người đăng ký, BehaviorSubject — sự kiện cuối cùng cộng với các sự kiện mới. Relay là một biến thể của Subject không phát ra .error hoặc .completed, đảm bảo tính liên tục của luồng. BehaviorRelay lưu trữ giá trị hiện tại và phù hợp cho UI điều khiển bằng trạng thái.

DisposeBag

DisposeBag là một tập hợp các Disposable tự động hủy tất cả đăng ký khi được giải phóng. Trong iOS, DisposeBag thường được thêm vào UIViewController hoặc UIView. Khi màn hình đóng, DisposeBag được dọn dẹp — điều này ngăn rò rỉ bộ nhớ và truy cập vào các phần tử UI không còn tồn tại.

Ví dụ mã RxSwift

Dưới đây là ví dụ về tạo Observable từ một mảng dữ liệu sử dụng toán tử map để biến đổi chuỗi:

swift
let observable = Observable.of("Swift", "RxSwift", "Reactive")

observable
    .map { $0.uppercased() }
    .subscribe(onNext: { value in
        print("Received: \(value)")
    })
    .disposed(by: disposeBag)

Ví dụ thứ hai minh họa việc kết hợp hai yêu cầu mạng bằng zip — toán tử chờ cho đến khi cả hai Observable phát ra giá trị và kết hợp kết quả thành một tuple:

swift
let first = fetchUser(id: "123")
let second = fetchPosts(userId: "123")

Observable
    .zip(first, second)
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: { user, posts in
        updateUI(user: user, posts: posts)
    })
    .disposed(by: disposeBag)

Ví dụ thứ ba cho thấy cách sử dụng BehaviorRelay để lưu trữ trạng thái và tự động cập nhật UI khi thay đổi: mỗi thay đổi state.accept() ngay lập tức được truyền đến người đăng ký, lý tưởng cho các mẫu State trong kiến trúc MVVM.

swift
let state = BehaviorRelay(value: "idle")

state
    .subscribe(onNext: { status in
        print("Status: \(status)")
    })
    .disposed(by: disposeBag)

state.accept("loading") // Prints: Status: loading

RxSwift so với các phương pháp khác

RxSwift khác với các phương pháp bất đồng bộ truyền thống (Delegation, NotificationCenter, Callback) ở tính khai báo và khả năng kết hợp. Không giống như Combine, RxSwift hỗ trợ iOS 9+ và có nhiều toán tử hơn. Tuy nhiên, Combine được tích hợp vào Foundation và SwiftUI ở cấp độ ngôn ngữ, mang lại lợi thế trong các dự án Apple mới.

Ưu điểm chính của RxSwift so với GCD (Grand Central Dispatch) là khả năng kết hợp và biến đổi luồng dữ liệu ở cấp độ trừu tượng, thay vì quản lý hàng đợi thủ công. Tuy nhiên, RxSwift đòi hỏi học các khái niệm phản ứng, làm tăng rào cản gia nhập cho nhóm.

Trong thực tế, RxSwift được sử dụng trong các dự án lớn nơi các chuỗi phản ứng kết nối sự kiện UI, logic kinh doanh và tương tác mạng trong một đường ống duy nhất. Ví dụ, trong các ứng dụng giao dịch, luồng báo giá được xử lý qua RxSwift: ticks đến từ WebSocket, qua bộ lọc, được nhóm theo khung thời gian và hiển thị trên biểu đồ theo thời gian thực. Kịch bản này khó triển khai qua Delegation hoặc NotificationCenter mà không mất tính dễ đọc.

Các lựa chọn thay thế cho RxSwift bao gồm Combine (iOS 13+), AsyncSequence từ Swift Concurrency (iOS 15+), cũng như các thư viện bên thứ ba như ReactiveSwift không phụ thuộc vào nền tảng Apple. Lựa chọn phụ thuộc vào phiên bản iOS tối thiểu được hỗ trợ và kinh nghiệm của nhà phát triển. Cho các dự án iOS 15+ mới, các nhóm thường chọn AsyncSequence — nó không yêu cầu cài đặt thư viện và sử dụng cấu trúc ngôn ngữ Swift gốc.

Các mẫu kiến trúc với RxSwift thường tuân theo MVVM hoặc Clean Architecture. ViewModel chứa tất cả logic kinh doanh dưới dạng chuỗi Observable, View đăng ký dữ liệu đã biến đổi. Mẫu Input-Output tách biệt sự kiện đầu vào (chạm, nhập văn bản) khỏi trạng thái đầu ra (văn bản nút, hiển thị loader). Cách tiếp cận này đơn giản hóa việc kiểm thử: ViewModel được kiểm thử mà không cần UI thông qua Schedulers ảo.

RxSwift phù hợp cho cả dự án nhỏ với vài màn hình và ứng dụng doanh nghiệp lớn với hàng chục mô-đun. Trong các dự án lớn, chuỗi phản ứng thấm nhuần toàn bộ kiến trúc: từ quan sát UserDefaults qua RxProperty đến yêu cầu mạng qua Moya (một wrapper RxSwift trên Alamofire). Mỗi mô-đun được cô lập và giao tiếp qua giao diện phản ứng, đơn giản hóa việc thay thế triển khai mà không thay đổi người đăng ký. Với kiến trúc phù hợp, RxSwift giảm lượng mã so với các phương pháp cổ điển vì không cần viết mã soạn sẵn cho KVO, Target-Action hoặc NotificationCenter.

RxSwift được sử dụng tích cực trong các dự án với RxDataSources — một thư viện cho công việc phản ứng với UITableView và UICollectionView. RxDataSources tự động tính toán sự khác biệt giữa tập hợp ô cũ và mới, đồng thời áp dụng các thay đổi có hoạt ảnh. Điều này giải phóng nhà phát triển khỏi công việc thủ công với beginUpdates/endUpdates và loại bỏ sự cố do dữ liệu không nhất quán.

Để gỡ lỗi chuỗi RxSwift, có toán tử debug() — nó ghi lại tất cả sự kiện: subscribe, next, error, completed, dispose. Đây là công cụ không thể thiếu khi phát triển các đường ống phản ứng phức tạp. debug(String) nhận một định danh xuất hiện trong nhật ký. Để phân tích bộ nhớ, RxSwift.Resources.total hiển thị tổng số Observable và Disposable đang hoạt động trong ứng dụng — giúp xác định rò rỉ khi DisposeBag không được dọn dẹp hoặc retain cycle giữ đăng ký. Toán tử bổ sung takeUntil(self.rx.deallocated) tự động hủy đăng ký khi giải phóng đối tượng — đây là một lớp bảo vệ bổ sung chống rò rỉ.

Thực hành tốt nhất với RxSwift

Khi viết mã RxSwift, điều quan trọng là tuân theo nguyên tắc một Observable cho mỗi đăng ký: mỗi ViewController không nên tạo nhiều hơn một Đăng ký cho cùng một Observable — điều này giảm nguy cơ điều kiện tranh chấp. Để ghi nhớ Observable, sử dụng toán tử share(), biến Observable lạnh thành nóng với bộ đệm replay kích thước 1. Khi làm việc với tài nguyên chia sẻ, hãy sử dụng connect() để kiểm soát việc bắt đầu phát — điều này đảm bảo tất cả người đăng ký kết nối trước sự kiện đầu tiên.

Kiểm thử mã RxSwift được thực hiện qua TestScheduler — một Scheduler ảo cho phép quản lý thời gian. testScheduler.createHotObservable(values) tạo Observable với chuỗi sự kiện được xác định trước theo thời gian ảo. testScheduler.start() bắt đầu xử lý. TestScheduler cho phép kiểm tra thứ tự và dấu thời gian ảo của các sự kiện mà không có độ trễ thực, làm cho bài kiểm tra nhanh và xác định.

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 lạnh: nó không phát ra sự kiện cho đến khi có đăng ký. Subject là nóng: nó phát ra sự kiện bất kể người đăng ký và cho phép chèn giá trị thủ công qua onNext. PublishSubject chỉ truyền các sự kiện mới, BehaviorSubject — sự kiện cuối cùng cộng với các sự kiện mới.

DisposeBag ngăn rò rỉ bộ nhớ trong RxSwift như thế nào?

DisposeBag lưu trữ tất cả đăng ký Disposable. Khi DisposeBag được giải phóng (ví dụ, khi đóng ViewController), tất cả đăng ký được lưu trữ tự động bị hủy. Điều này đảm bảo Observable không gửi sự kiện đến đối tượng UI đã bị phá hủy.

Nên chọn RxSwift hay Combine cho dự án iOS mới?

Nếu phiên bản iOS tối thiểu là 13+ và nhóm biết SwiftUI — hãy chọn Combine. Nếu dự án hỗ trợ iOS 12 trở xuống hoặc cần nhiều toán tử hơn — hãy chọn RxSwift. Combine cung cấp tích hợp tốt hơn với Foundation (URLSession, Timer, NotificationCenter).

Schedulers trong RxSwift hoạt động như thế nào?

Schedulers trừu tượng hóa các luồng thực thi. subscribeOn chỉ định Scheduler nào thực hiện đăng ký (thường là nền). observeOn xác định Scheduler nào nhận sự kiện (thường là MainScheduler cho cập nhật UI). SerialDispatchQueueScheduler hoạt động qua GCD.

Có thể sử dụng RxSwift với SwiftUI không?

Có, RxSwift có thể được tích hợp với SwiftUI qua ObservableObject. Sử dụng BehaviorRelay như các thuộc tính @Published: đăng ký Relay truyền thay đổi đến Combine, và SwiftUI vẽ lại View qua @ObservedObject. Đây là mẫu di chuyển phổ biến từ UIKit sang SwiftUI.

Tổng kết

  • RxSwift — thư viện lập trình phản ứng dựa trên Reactive Extensions và mẫu Observable
  • Observable phát ra ba loại tín hiệu: .next, .error và .completed
  • Subject (PublishSubject, BehaviorSubject) kết hợp Observable và Observer cho luồng nóng
  • DisposeBag quản lý vòng đời đăng ký và ngăn rò rỉ bộ nhớ
  • Toán tử (map, filter, flatMap, zip) cho phép xây dựng chuỗi xử lý khai báo
  • Schedulers chuyển thực thi giữa hàng đợi nền và luồng UI
  • Cho phát triển iOS 13+ mới, hãy cân nhắc Combine như lựa chọn thay thế tích hợp sẵn

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