البرمجة التفاعلية في Swift: Combine و RxSwift لنظامي iOS/macOS

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

البرمجة التفاعلية في Swift: Combine و RxSwift

\n\n

البرمجة التفاعلية هي نموذج يركز على تدفقات البيانات غير المتزامنة ونشر التغييرات. في نظام Swift البيئي (iOS/macOS)، الأدوات الرئيسية لتنفيذ هذا النموذج هي إطار Combine (المدمج في Apple SDK) والمكتبة الخارجية RxSwift. تتيح كلتا الأداتين وصف معالجة الأحداث بطريقة تصريحية، مما يقلل من عدد دوال الاسترجاع (callback) ويجعل الكود أكثر قابلية للقراءة وقابلية للتنبؤ.

\n\n

في هذه المقالة، سنستعرض المفاهيم الأساسية للبرمجة التفاعلية، ونقارن بين Combine و RxSwift، ونقدم أمثلة عملية لنظامي iOS و macOS.

\n\n

المفاهيم الأساسية

\n

يقوم النهج التفاعلي على ثلاث كيانات:

\n\n
    \n
  • الناشر (Publisher/Observable) — مصدر البيانات الذي يولد الأحداث (القيم، الأخطاء، الإكمال).
  • \n
  • المشترك (Subscriber/Observer) — المستهلك الذي يستجيب للأحداث.
  • \n
  • المُشغّل (Operator) — دالة تحول تدفق البيانات (التصفية، التحويل، الدمج).
  • \n
\n\n

مثال على ناشر بسيط في Combine:

\n
import Combine\n\nlet publisher = Just("Hello, Reactive World!")\nlet subscription = publisher.sink { value in\n    print(value)\n}\n// الإخراج: Hello, Reactive World!
\n\n

Combine مقابل RxSwift: مقارنة

\n

كلا الإطارين يحلان مهامًا متشابهة، لكن بينهما اختلافات:

\n\n
    \n
  • Combine — إطار أصلي من Apple (iOS 13+، macOS 10.15+). يستخدم كتابة صارمة ويتكامل مع SwiftUI و URLSession.
  • \n
  • RxSwift — مكتبة متعددة المنصات مع مجتمع كبير. تدعم إصدارات iOS الأقدم (بدءًا من iOS 8).
  • \n
  • الأداء: Combine مُحسّن لمعالجات Apple Silicon، بينما RxSwift قد يكون أكثر مرونة في السيناريوهات المخصصة.
  • \n
\n\n

أمثلة برمجية لنظامي iOS/macOS

\n\n

1. معالجة تفاعلية لحقل نصي (Combine + UIKit)

\n

الاشتراك في تغييرات النص في UITextField:

\n
import UIKit\nimport Combine\n\nclass ViewController: UIViewController {\n    @IBOutlet weak var textField: UITextField!\n    private var cancellables = Set<AnyCancellable>()\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: textField)\n            .compactMap { ($0.object as? UITextField)?.text }\n            .debounce(for: .milliseconds(500), scheduler: RunLoop.main)\n            .sink { text in\n                print("المستخدم أدخل: \\(text)")\n                // هنا يمكن إجراء طلب شبكة أو تحديث واجهة المستخدم\n            }\n            .store(in: &cancellables)\n    }\n}
\n\n

2. دمج عدة تدفقات (RxSwift لنظام macOS)

\n

مثال على دمج تسلسلين observable:

\n
import RxSwift\n\nlet disposeBag = DisposeBag()\n\nlet firstObservable = Observable.of(1, 2, 3)\nlet secondObservable = Observable.of("A", "B", "C")\n\nObservable.zip(firstObservable, secondObservable)\n    .subscribe(onNext: { (number, letter) in\n        print("\\(number) -> \\(letter)")\n    })\n    .disposed(by: disposeBag)\n\n// الإخراج:\n// 1 -> A\n// 2 -> B\n// 3 -> C
\n\n

3. معالجة طلب شبكة باستخدام Combine

\n

استخدام URLSession لتحميل البيانات:

\n
import Combine\nimport Foundation\n\nstruct Post: Decodable {\n    let id: Int\n    let title: String\n}\n\nfunc fetchPosts() -> AnyPublisher<[Post], Error> {\n    let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!\n    return URLSession.shared.dataTaskPublisher(for: url)\n        .map(\\.data)\n        .decode(type: [Post].self, decoder: JSONDecoder())\n        .eraseToAnyPublisher()\n}\n                    

توصيات