Combine یک فریمورک برنامهنویسی واکنشی از Apple است که در iOS 13 معرفی شد. به گفته Apple Documentation, 2025, Combine یک API اعلامی واحد برای پردازش رویدادهای ناهمگام ارائه میدهد. Publisher منبع داده را مشخص میکند و Subscriber برای دریافت آنها مشترک میشود.
نکات اصلی
Combine یک فریمورک اعلامی Swift برای پردازش رویدادهای ناهمگام در طول زمان است. برخلاف رویکردهای مبتنی بر callback، Combine امکان توصیف خطوط لوله پردازش داده را از طریق زنجیرهای از عملگرها فراهم میکند. این فریمورک با Foundation (URLSession، Timer، NotificationCenter) و SwiftUI (ObservableObject، @Published) یکپارچه شده است.
هر نوعی که پروتکل Publisher را پیادهسازی میکند، باید Output (نوع مقادیر) و Failure (نوع خطا) را مشخص کند. Publisher تا زمان اشتراک فعال نیست — فقط پس از فراخوانی subscribe شروع به انتشار رویدادها میکند. این معنای سرد است که مشخصه جریانهای واکنشی است و کارایی را افزایش میدهد.
Subscriber رویدادها را از طریق سه روش دریافت میکند: receive(subscription:) — تأیید اشتراک با مدیریت demand; receive(_:) — دریافت مقدار جدید; receive(completion:) — پایان جریان با موفقیت یا خطا. Demand تعداد مقادیری را که Subscriber آماده دریافت است مشخص میکند — این مکانیزم backpressure است.
Apple Publisherهای داخلی متعددی ارائه میدهد: Just یک مقدار منتشر میکند و پایان مییابد، Future — نتیجه ناهمگام با بسته، Deferred — ایجاد تأخیری Publisher تا لحظه اشتراک. URLSession.dataTaskPublisher درخواست شبکه را به جریان واکنشی تبدیل میکند. Timer.publish یک تایمر دورهای ایجاد میکند. NotificationCenter.default.publisher اعلانها را به Publisher تبدیل میکند. این یکپارچگیها امکان اشتراک در رویدادها را بدون پل دستی فراهم میکنند.
در Combine Publisher و Subscriber توسط پروتکل Subscription به هم متصل میشوند. Subscription یک شیء پیونددهنده است که جریان داده را کنترل میکند. توسعهدهنده نیازی به ایجاد انواع Publisher خود ندارد — Apple Publisherهای داخلی Just, Future, Deferred, Fail, Empty و همچنین Publisher برای URLSession و Timer را فراهم کرده است.
Subject یک Publisher است که میتوان به صورت دستی مقادیر را به آن ارسال کرد. PassthroughSubject وضعیت را ذخیره نمیکند: مشترک فقط رویدادهایی را دریافت میکند که پس از اشتراک رخ دادهاند. CurrentValueSubject مشابه BehaviorRelay در RxSwift، مقدار فعلی را ذخیره میکند و بلافاصله آن را به مشترک جدید منتقل میکند.
مکانیزم backpressure در Combine سرعت انتقال داده را تنظیم میکند. Subscriber از طریق subscription.request(.unlimited) یا subscription.request(.max(N)) به Publisher اطلاع میدهد که چند مقدار آماده پردازش است. این کار از سرریز بافر در سرعت نابرابر تولیدکننده و مصرفکننده جلوگیری میکند.
Combine شامل بیش از 100 عملگر تقسیمبندی شده به دستهها: تبدیل (map, tryMap, flatMap)، فیلتر (filter, compactMap, removeDuplicates)، ترکیب (combineLatest, merge, zip)، مدیریت زمان (debounce, throttle, delay) و مدیریت خطا (catch, replaceError, retry) است.
عملگر combineLatest آخرین مقادیر دو Publisher را ترکیب میکند — هر بار که هر یک از آنها مقدار جدیدی منتشر میکند، بسته با هر دو مقدار بهروز فراخوانی میشود. این عملگر در اعتبارسنجی فرمها که نیاز به ردیابی وضعیت چندین فیلد ورودی همزمان است ضروری میباشد.
عملگر debounce انتشار مقادیر را تا زمانی که فاصله مشخصی بدون رویداد جدید بگذرد به تأخیر میاندازد. این برای نوارهای جستجو حیاتی است: درخواست به سرور فقط پس از توقف تایپ کاربر به مدت 300-500 میلیثانیه ارسال میشود که بار را 5-10 برابر کاهش میدهد.
Combine چندین استراتژی مدیریت خطا در سطح عملگرها ارائه میدهد. catch Failure را گرفته و Publisher را با یک جایگزین تعویض میکند — جریان بدون کرش ادامه مییابد. replaceError(with:) یک مقدار پیشفرض را به جای خطا قرار میدهد. retry(_:) اشتراک را در صورت خطا به تعداد مشخصی تکرار میکند. مهم: نوع خطا Never در امضای Publisher تضمین میکند که جریان هرگز با خطا خاتمه نمییابد — این امکان استفاده از Publisher در SwiftUI بدون مدیریت Failure را فراهم میکند.
اولین نمونه کار پایه با Just — Publisher که یک مقدار منتشر میکند و پایان مییابد:
let publisher = Just("Hello Combine")
publisher
.sink(receiveCompletion: { completion in
print("تکمیل شد: \(completion)")
}, receiveValue: { value in
print("دریافت شد: \(value)")
})
دومین نمونه یکپارچگی Combine با URLSession برای درخواست شبکه با پردازش نتیجه در نخ اصلی را نشان میدهد:
let url = URL(string: "https://api.example.com")!
URLSession.shared
.dataTaskPublisher(for: url)
.map { $0.data }
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
if case .failure(let error) = completion {
print("خطا: \(error)")
}
}, receiveValue: { data in
print("داده دریافت شد: \(data.count)")
})
سومین نمونه — استفاده از CurrentValueSubject برای مدیریت وضعیت:
let counter = CurrentValueSubject<Int, Never>(0)
counter
.sink { value in
print("شمارنده: \(value)")
}
counter.send(1) // نمایش میدهد: شمارنده: 1
counter.send(2) // نمایش میدهد: شمارنده: 2
print(counter.value) // نمایش میدهد: 2
Combine و RxSwift یک مسئله را حل میکنند — برنامهنویسی واکنشی، اما با رویکردهای متفاوت. Combine یک فریمورک بومی Apple است که در سیستم تعبیه شده: نیاز به نصب وابستگیها ندارد، با SwiftUI و Foundation یکپارچه است. RxSwift یک کتابخانه شخص ثالث با پشتیبانی از iOS 9+ و مجموعه گستردهتری از عملگرها است.
عملکرد Combine در سناریوهای معمولی به دلیل پیادهسازی بومی در C بالاتر است. RxSwift ابزارهای بیشتری برای اشکالزدایی فراهم میکند (RxSwift.Resources.total, Debug)، اما معماری شیگرای آن ممکن است در جریانهای داده بزرگ کارایی کمتری داشته باشد. انتخاب بین آنها سازشی بین قابلیتها و یکپارچگی است.
تفاوت مهم — مدل backpressure است. در Combine Subscriber demand را از طریق Subscription مدیریت میکند که کنترل صریح بر سرعت جریان میدهد. در RxSwift backpressure به طور پیشفرض کنترل نمیشود — Observable همه مقادیر را منتشر میکند و Subscriber آنها را هنگام دریافت پردازش میکند. برای جریانهای داده بزرگ Combine قابلپیشبینیتر و از نظر حافظه ایمنتر است.
Combine در سطح زبان با SwiftUI یکپارچه شده است. @Published یک Publisher تولید میکند، ObservableObject Publisher objectWillChange را فراهم میکند. SwiftUI View به طور خودکار در این Publisherها مشترک میشود و در هنگام تغییرات دوباره ترسیم میکند. برای UIKit پوششهای شخص ثالث مانند CombineCocoa وجود دارد، اما Combine در اصل برای SwiftUI طراحی شده است، بنابراین یکپارچگی آن در UIKit به کد اضافی نیاز دارد. RxSwift در مقابل، اکوسیستم غنی برای UIKit دارد: RxCocoa پوششهای واکنشی برای تمام عناصر UI فراهم میکند.
Combine از یکپارچگی با Core Data از طریق NSFetchedResultsController Publisher پشتیبانی میکند. Publisher با هر تغییری در پشته Core Data — افزودن، حذف، بهروزرسانی رکوردها — دادههای جدید منتشر میکند. این امکان ساخت لیستهای واکنشی بدون فراخوانی دستی reloadData را فراهم میکند. با ترکیب Combine با NotificationCenter Publisher برای UIApplication.willResignActiveNotification، توسعهدهنده یک لایه واکنشی برای کل چرخه حیات برنامه بدون دلیگیت و callback ایجاد میکند. برای کلاسهای ObservableObject، SwiftUI به طور خودکار View را در هنگام تغییر خصوصیات @Published بهروز میکند — Combine تمام اتصال را بدون یک خط کد دستی فراهم میکند. تست ماژولار کد Combine از طریق XCTestExpectation و Publisher.sink در موارد تست با جداسازی Scheduler از طریق ImmediateScheduler انجام میشود.
هنگام کار با Combine در پروژههای UIKit، توسعهدهندگان اغلب از اشتراک از طریق sink استفاده میکنند و AnyCancellable را در Set ذخیره میکنند. الگوی معمول: ViewController یک view ایجاد میکند، cancellables را ذخیره میکند، در Publisher از ViewModel مشترک میشود. در deinit همه اشتراکها به طور خودکار از طریق مجموعه Cancellables لغو میشوند. برای کار صحیح با UIControl در Combine میتوان از UIControl.Event Publisher از طریق توسعهدهنده publisher(for:) استفاده کرد.
اشکالزدایی Combine از طریق عملگر print() یا handleEvents() انجام میشود. print(String) تمام رویدادها را ثبت میکند: receive subscription, request demand, receive value, receive completion. handleEvents کنترل دقیقتری میدهد: میتوان بستههایی برای هر مرحله از چرخه حیات Publisher مشخص کرد. برای تست Combine، CombineExpectations وجود دارد — کتابخانهای که امکان بررسی انتشار مقادیر مورد انتظار توسط Publisher در تستها با زمان مجازی و کنترل demand را فراهم میکند.
Combine به طور فعال در SwiftUI برای مدیریت فرمها استفاده میشود: هر خصوصیت @Published یک Publisher تولید میکند، SwiftUI از طریق View.body در آن مشترک میشود. با ترکیب چندین Publisher از طریق combineLatest، اعتبارسنجی فرم اعلامی میشود: هر Publisher یک فیلد را ردیابی میکند، combineLatest تمام مقادیر را جمعآوری میکند، map آنها را بررسی کرده و وضعیت دکمه Submit را برمیگرداند. Publishers.Merge چندین Publisher از یک نوع را در یکی ترکیب میکند — برای جمعآوری رویدادها از کنترلهای مختلف در یک جریان مفید است.
برای یکپارچگی Combine با UIKit از UIControl Publisher از طریق توسعهدهنده استفاده کنید: button.publisher(for: .touchUpInside) یک Publisher برمیگرداند که هنگام فشار رویداد منتشر میکند. CombineCocoa — یک کتابخانه اجتماعی است که Publisher برای تمام رویدادهای UIControl، UITextView.text، UIScrollView.contentOffset فراهم میکند. هنگام لغو اشتراک، cancellables Store در deinit پاک میشود و تضمین میکند که هیچ اشتراکی از مالک خود بیشتر زنده نمیماند. برای UIControl با وضعیتهای متعدد از Publishers.MergeMany برای ترکیب Publisherها در یک آرایه استفاده کنید.
سوالات متداول
Combine از iOS 13, macOS 10.15, tvOS 13 و watchOS 6 در دسترس است. این امر استفاده از آن را در پروژههایی که نیاز به پشتیبانی از نسخههای قدیمیتر دارند محدود میکند. برای iOS 12 و پایینتر از RxSwift یا کتابخانههای شخص ثالث استفاده میشود.
PassthroughSubject وضعیت را ذخیره نمیکند و آخرین مقدار را به مشترکان جدید تکرار نمیکند — آنها فقط رویدادهای آینده را دریافت میکنند. CurrentValueSubject مقدار فعلی را ذخیره میکند و بلافاصله آن را به مشترک جدید منتقل میکند. CurrentValueSubject.value امکان خواندن و نوشتن مقدار فعلی به صورت همزمان را فراهم میکند.
Combine در پایه SwiftUI قرار دارد: @Published یک Publisher تولید میکند، ObservableObject از Publisher objectWillChange استفاده میکند. SwiftUI View به طور خودکار در @ObservedObject و @StateObject از طریق خط لوله Combine مشترک میشود و View را در هنگام تغییر خصوصیات دوباره ترسیم میکند.
Backpressure — مکانیزم مدیریت سرعت انتقال داده است. Subscriber به Subscription اطلاع میدهد که چند مقدار آماده پردازش است (demand). Publisher نمیتواند بیش از مقدار درخواست شده منتشر کند. این هنگام کار با جریانهای داده بزرگ از سوکتهای شبکه حیاتی است.
عملگر catch خطا را گرفته و Publisher را با fallback جایگزین میکند. replaceError خطا را با مقدار پیشفرض جایگزین میکند. retry اشتراک را تعداد مشخصی بار در صورت خطا تکرار میکند. تمام عملگرها باید قبل از subscribe قرار داده شوند تا از کرش در Failure جلوگیری شود.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید