RxSwift هي مكتبة برمجة تفاعلية لنظام iOS تطبق نمط Observable والعوامل الوظيفية للعمل مع تدفقات البيانات غير المتزامنة. إنها تنقل مفاهيم ReactiveX (Rx) إلى لغة Swift، مما يوفر واجهة برمجة تطبيقات موحدة لمعالجة الأحداث من واجهة المستخدم وطلبات الشبكة وقواعد البيانات والمؤقتات. وفقًا لـ ReactiveX، 2025، تُستخدم المكتبة في أكثر من 60,000 مشروع على GitHub ولا تزال المعيار للبرمجة التفاعلية في Swift حتى ظهور Combine الأصلي. RxSwift يحل محل المفوضين والإغلاقات والإشعارات بسلسلة معالجة أحداث واحدة.
الخلاصة
RxSwift هو منفذ Swift لمكتبة ReactiveX (Rx) التي أنشأتها Microsoft لـ .NET في عام 2012. الفكرة الأساسية لـ Rx هي تمثيل أي مصدر بيانات غير متزامن كسلسلة Observable يمكن تطبيق العوامل الوظيفية عليها. في تطوير iOS، يُستخدم RxSwift لربط أحداث واجهة المستخدم (النقر على الأزرار، إدخال النص، الإيماءات) بمنطق التطبيق دون مفوضين صريحين وtarget-action.
تتكون المكتبة من ثلاث وحدات: RxSwift (النواة — Observable، Operator، Scheduler)، RxCocoa (التكامل مع UIKit — امتدادات rx لـ UIButton، UITextField، UITableView) و RxRelay (Subject بدون أحداث نهائية). هذا الفصل يسمح باستخدام النواة في Swift من جانب الخادم والاختبارات، مع ربط غلاف واجهة المستخدم فقط لتطبيقات iOS.
وفقًا لاستطلاع Stack Overflow، 2025، فإن RxSwift من بين أفضل 5 مكتبات خارجية الأكثر استخدامًا لنظام iOS. السبب الرئيسي لشعبيتها هو المعالجة الموحدة لجميع الأنماط غير المتزامنة: طلبات الشبكة عبر URLSession، الرسوم المتحركة عبر UIViewPropertyAnimator، الإشعارات عبر NotificationCenter والمفوضين عبر DelegateProxy — كل هذا يختزل إلى Observable بدورة حياة يمكن التنبؤ بها.
البرمجة التفاعلية هي نموذج يتفاعل فيه البرنامج مع تغييرات البيانات بدلاً من الاستعلام عنها. بدلاً من كتابة «الحصول على البيانات → المعالجة → تحديث واجهة المستخدم»، يصف المطور سلسلة تحويلات: «عندما تتغير البيانات، طبق الفلتر، ثم map، ثم تحديث واجهة المستخدم». ينفذ RxSwift هذا النموذج من خلال سلاسل Observable ذات التنفيذ البطيء — لا يحدث شيء حتى يظهر مشترك.
Observable هو النوع الأساسي في RxSwift الذي يمثل سلسلة من الأحداث عبر الزمن. يمكن لـ Observable إرسال ثلاثة أنواع من الأحداث: next (قيمة جديدة)، error (خطأ ينهي التدفق) و completed (إكمال ناجح). هناك Observable محدودة (تكتمل بعد إرسال جميع القيم) و Observable غير محدودة (مثل أحداث واجهة المستخدم — لا تكتمل أبدًا).
تشمل دورة الحياة لـ Observable ثلاث مراحل: الإنشاء (create، just، from)، التحويل (العوامل map، filter، flatMap) والاشتراك (subscribe). بدون اشتراك، لا يقوم Observable بأي إجراءات — إنها سلسلة كسولة. بعد الاشتراك، يبدأ Observable في إرسال الأحداث إلى المشترك حتى يكتمل أو يلغي المشترك الاشتراك عبر Disposable.
import RxSwift
// إنشاء Observable من مصفوفة
let numbers = Observable.from([1, 2, 3, 4, 5])
// التحويل عبر العوامل
let squared = numbers
.filter { $0 % 2 == 0 }
.map { $0 * $0 }
// الاشتراك مع معالجة الأحداث
let disposable = squared
.subscribe(onNext: { print($0) },
onError: { print("Error: \($0)") },
onCompleted: { print("Done") })
Subject هو نوع يكون في نفس الوقت Observable (يمكن الاشتراك فيه) و Observer (يمكن إرسال الأحداث إليه). يوفر RxSwift أربعة أنواع من Subject: PublishSubject (أحداث جديدة فقط)، BehaviorSubject (بقيمة أولية)، ReplaySubject (تخزين آخر N حدث في المخزن المؤقت) و AsyncSubject (آخر قيمة فقط قبل الإكمال). Subject مفيد لدمج الكود الأمرّي (الإغلاقات، المفوضون) في سلسلة تفاعلية.
Disposable هو رمز إلغاء الاشتراك. عندما لا يريد المشترك تلقي الأحداث بعد الآن، يستدعي disposable.dispose(). عمليًا، يُستخدم DisposeBag: مجموعة من Disposable تلغي تلقائيًا جميع الاشتراكات عند إلغاء تهيئة المالك (مثل UIViewController). هذا يمنع تسرب الذاكرة الحتمي مع الإدارة اليدوية للاشتراكات.
| نوع Subject | قيمة أولية | يعيد للمشترك | الاستخدام |
|---|---|---|---|
| PublishSubject | لا | أحداث جديدة فقط | أحداث واجهة المستخدم، إشعارات نادرة |
| BehaviorSubject | نعم | آخر + جديد | الحالة، تدفق البيانات |
| ReplaySubject | لا | مخزن N + جديد | تخزين مؤقت للسجل |
| AsyncSubject | لا | آخر فقط | مهام حسابية |
| PublishRelay | لا | جديد فقط | بدون error/completed |
العوامل في RxSwift هي دوال تأخذ Observable واحدًا وتعيد Observable آخر، محولة تدفق البيانات. بدمج العوامل، يبني المطور سلاسل معالجة تصريحية بدون متغيرات وسيطة وحالات سباق. جميع العوامل كسولة: السلسلة تُبنى أثناء الوصف وتُنفذ عند الاشتراك.
عوامل التحويل تغير كل حدث في التدفق. map يطبق دالة على كل عنصر، flatMap يفك Observable من كل عنصر إلى تدفق مسطح واحد، scan يراكم النتائج الوسيطة (مشابه لـ reduce ولكنه يُصدر كل خطوة). buffer يجمع العناصر حسب الوقت أو العدد، window يقسم التدفق إلى Observable متداخلة حسب النوافذ.
// مثال لسلسلة العوامل: بحث مع 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)
عوامل التصفية تمرر فقط الأحداث التي تفي بشرط. filter يصفّي حسب المسند، distinctUntilChanged يمرر فقط القيم المختلفة عن السابقة، take و takeWhile يحدان من عدد الأحداث. skip و skipWhile يتخطيان أول N حدث أو الأحداث حتى يتحقق شرط. لمعالجة الأخطاء، تُستخدم catchError (اعتراض واستبدال) و retry (إعادة محاولة التسلسل عند الخطأ).
عوامل الدمج تدمج عدة Observables في واحد. combineLatest يدمج أحدث القيم من تدفقات متعددة في مجموعة، zip يزاوج العناصر بنفس المؤشرات، merge يدمج تدفقات متعددة في واحد بترتيب وصول الأحداث. withLatestFrom يدمج حدثًا من التدفق الرئيسي مع آخر قيمة من تدفق آخر — مفيد لأحداث واجهة المستخدم مع الحالة الحالية.
| الفئة | العامل | الوظيفة |
|---|---|---|
| تحويل | map | يحول كل قيمة عبر دالة |
| تحويل | flatMap | يفك Observables المتداخلة إلى تدفق مسطح |
| تصفية | filter | يمرر القيم حسب المسند |
| تصفية | distinctUntilChanged | يمرر القيم المتغيرة فقط |
| دمج | combineLatest | يدمج أحدث القيم من 2+ تدفقات |
| دمج | zip | يزاوج العناصر حسب المؤشر |
| تحكم | debounce | يؤخر الأحداث حتى توقف في التدفق |
| تحكم | take | يأخذ أول N حدث ويكمل التدفق |
Scheduler في RxSwift هو تجريد فوق خيط التنفيذ (أو قائمة الانتظار). يحدد Scheduler في أي خيط يتم تنفيذ إنشاء الأحداث والتحويل والاشتراك. على عكس GCD، حيث يحدد المطور صراحةً DispatchQueue، يستخدم RxSwift معلمتين: subscribeOn (في أي خيط يتم تنفيذ Observable) و observeOn (في أي خيط يتم استدعاء المشترك).
MainScheduler ينفذ الكود على الخيط الرئيسي — إلزامي لتحديث UIKit (جميع تغييرات واجهة المستخدم يجب أن تحدث على الخيط الرئيسي). SerialDispatchQueueScheduler يغلف قائمة انتظار GCD تسلسلية، ConcurrentDispatchQueueScheduler يغلف قائمة انتظار متزامنة. للمهام الخلفية، يُستخدم ConcurrentDispatchQueueScheduler مع qos: .background أو .utility.
// النمط النموذجي: عمل خلفي + واجهة مستخدم على main
apiService.fetchData()
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { data in
self.tableView.reloadData()
self.loadingIndicator.stopAnimating()
})
.disposed(by: disposeBag)
الاستخدام الصحيح لـ Scheduler يمنع حظر واجهة المستخدم أثناء طلبات الشبكة والحسابات الثقيلة. subscribeOn يؤثر على كل المنبع (جميع العوامل قبل observeOn تُنفذ على المجدول المحدد). observeOn يحول المصب — جميع العوامل بعد observeOn تُنفذ على المجدول المحدد. يمكن أن تحتوي السلسلة على عدة observeOn للتبديل بين الخيوط في مراحل تحويل مختلفة.
SerialDispatchQueueScheduler يضمن المعالجة التسلسلية للأحداث، وهو أمر مهم لسلامة الخيوط للموارد المشتركة. للعمليات عالية التحميل (معالجة الصور، تحليل JSON) استخدم ConcurrentDispatchQueueScheduler — RxSwift سيحافظ على ترتيب الأحداث داخل Observable واحد، لكن Observables مختلفة قد تتم معالجتها بالتوازي.
RxSwift في مشاريع iOS يُستخدم غالبًا لربط واجهة المستخدم بالبيانات عبر سلاسل تفاعلية. يوفر RxCocoa امتدادات rx لجميع مكونات UIKit القياسية: rx.tap لـ UIButton، rx.text لـ UITextField، rx.selectedRow لـ UIPickerView. هذا يسمح بالتخلي عن @IBAction والمفوضين، واستبدالهم باشتراكات تصريحية.
MVVM (Model-View-ViewModel) هو نمط معماري يدير فيه ViewModel الحالة ومنطق الأعمال، ويشترك View في الخصائص التفاعلية لـ ViewModel. RxSwift يتناسب تمامًا مع MVVM: ViewModel ينشر Observable أو Driver للبيانات، ويشترك View فيها عبر bind. ViewModel ليس لديه مرجع إلى View — يُرجع Observable التي يستهلكها View.
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
}
}
}
// في ViewController:
viewModel.isFormValid
.bind(to: loginButton.rx.isEnabled)
.disposed(by: disposeBag)
طلبات الشبكة هي ثاني أكثر حالات استخدام RxSwift شيوعًا. URLSession.rx.response يغلف طلب HTTP في Observable يُرجع (response, data) عند النجاح أو error عند الفشل. بالدمج مع Codable والعامل map، يتم الحصول على طبقة API تفاعلية مضغوطة: Observable<MyModel> بدون callbacks ومعالجة أخطاء في كل طريقة. عند خطأ الشبكة، العامل retry(3) يعيد محاولة الطلب تلقائيًا ثلاث مرات مع تأخير أسي.
Combine هو إطار Apple الأصلي الذي تم تقديمه في iOS 13. يحل نفس المهام التي يحلها RxSwift: العمل مع الأحداث غير المتزامنة عبر Publisher و Subscriber والعوامل. ومع ذلك، لدى Combine اختلافات رئيسية: كتابة أخطاء صارمة عبر نوع Failure، دعم Swift Concurrency المدمج (async/await) والتكامل مع SwiftUI عبر @Published و ObservableObject.
RxSwift يتفوق في التوافق مع الإصدارات السابقة — يدعم iOS 8+، بينما يتطلب Combine iOS 13+. RxSwift لديه نظام بيئي أغنى من الامتدادات الخارجية (RxDataSources، RxGesture، RxAnimated) وتوثيق مفصل للعوامل. للمشاريع التي تدعم إصدارات iOS القديمة، يظل RxSwift الخيار الوحيد.
للمشاريع الجديدة على iOS 13+، توصي Apple باستخدام Combine. إنه متكامل بإحكام مع SwiftUI، وله حجم ثنائي أصغر ودعم رسمي. ومع ذلك، فإن ترحيل كود RxSwift الحالي إلى Combine يتطلب إعادة كتابة جميع Observable → Publisher، ونظام RxCocoa البيئي ليس له مكافئ كامل في Combine — UIKit ليس لديه Publisher أصلي لجميع مكونات واجهة المستخدم.
| الميزة | RxSwift | Combine |
|---|---|---|
| الحد الأدنى iOS | iOS 8+ | iOS 13+ |
| نوع الخطأ | Error (أي) | Generic Failure |
| امتدادات UI | RxCocoa (UIKit, AppKit) | @Published (SwiftUI) |
| العوامل | 400+ عامل | ~100 عامل |
| Swift Concurrency | عبر bridge | دعم أصلي |
| الحالة | جهة خارجية | Apple رسمي |
الأسئلة الشائعة
Observable هو مصدر للأحداث مع تنفيذ بطيء. Subject هو في نفس الوقت Observable و Observer — يمكنك الاشتراك فيه وإرسال أحداث جديدة إليه يدويًا. Subject مفيد لدمج الكود الأمرّي في السلاسل التفاعلية.
RxSwift يُختار عند الحاجة لدعم iOS 11-12، أو عند وجود قاعدة كود RxSwift حالية، أو عند الحاجة إلى نظام بيئي غني بالعوامل (400+ مقابل ~100 في Combine). للمشاريع الجديدة على iOS 13+ يُفضل Combine.
DisposeBag هو مجموعة من رموز Disposable تلغي تلقائيًا جميع الاشتراكات عند إلغاء تهيئة المالك. بدون DisposeBag، ينشئ الاشتراك مرجعًا قويًا للإغلاق، مما يؤدي إلى تسرب الذاكرة عند تدمير UIViewController.
استخدم catchError لاستبدال الخطأ بقيمة افتراضية، retry لإعادة محاولة تنفيذ Observable، materialize لتحويل الخطأ إلى حدث. في طبقة واجهة المستخدم، Driver و Signal لا ينقلان الأخطاء — تتم معالجتها داخليًا.
Driver هو نوع خاص من Observable يضمن التنفيذ على MainScheduler، وغياب الأخطاء ومشاركة الموارد. يضمن Driver أن تحديثات واجهة المستخدم تحدث على الخيط الرئيسي. Observable لا يوفر هذه الضمانات — يلزم observeOn.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.