Combine Apple का नेटिव रिएक्टिव प्रोग्रामिंग फ्रेमवर्क है, जिसे iOS 13, macOS Catalina, tvOS 13 और watchOS 6 में पेश किया गया। यह Publisher और Subscriber पैटर्न के माध्यम से एसिंक्रोनस इवेंट्स को हैंडल करने के लिए एक डिक्लेरेटिव Swift API प्रदान करता है, डेलीगेट्स, क्लोज़र्स और NotificationCenter को एक एकीकृत श्रृंखला से बदलता है। Apple, 2025 के अनुसार, Combine SwiftUI और आधुनिक iOS आर्किटेक्चर की नींव है, जो async/await और Structured Concurrency के साथ मिलकर काम करता है। यह फ्रेमवर्क थ्रेड-सुरक्षा गारंटी के साथ एसिंक्रोनस ऑपरेशन की संरचना के लिए डिज़ाइन किया गया है।
मुख्य बिंदु
Combine एक डिक्लेरेटिव रिएक्टिव प्रोग्रामिंग फ्रेमवर्क है जो Apple SDK में निर्मित है। यह रिएक्टिव स्ट्रीम पैटर्न लागू करता है: Publisher मान उत्पन्न करता है, Subscriber उनका उपभोग करता है, और ऑपरेटर उनके बीच स्ट्रीम को बदलते हैं। Combine कॉलबैक और डेलीगेट्स की समस्या को किसी भी एसिंक्रोनस इवेंट — नेटवर्क प्रतिक्रियाओं से लेकर UI परिवर्तनों तक — के लिए एक एकीकृत संरचना मॉडल प्रदान करके हल करता है।
Combine के आगमन से पहले, iOS डेवलपर तृतीय-पक्ष लाइब्रेरी, मुख्य रूप से RxSwift का उपयोग करते थे। Apple ने Combine को पारिस्थितिकी तंत्र में गहन एकीकरण के साथ एक देशी विकल्प के रूप में बनाया: फ्रेमवर्क @objc ब्रिज के माध्यम से Objective-C का समर्थन करता है, KVO (NSObject.keyValuePublisher के माध्यम से Key-Value Observing) और NotificationCenter के साथ काम करता है, और SwiftUI की नींव भी है। SwiftUI में प्रकाशित सभी UIKit घटक व्यू अपडेट के लिए अंडर द हुड Combine का उपयोग करते हैं।
Combine Swift Concurrency को ध्यान में रखकर डिज़ाइन किया गया है: iOS 15 से शुरू करके, Publisher को .values के माध्यम से AsyncSequence में परिवर्तित किया जा सकता है और for-await-in लूप में उपयोग किया जा सकता है। async फ़ंक्शन का Publisher में विपरीत रूपांतरण Future के माध्यम से किया जाता है। Apple WWDC 2024 के अनुसार, एकल एसिंक्रोनस कॉल के लिए async/await की शुरूआत के बावजूद, Combine UIKit अनुप्रयोगों में स्ट्रीमिंग डेटा को संभालने के लिए अनुशंसित फ्रेमवर्क बना हुआ है।
Combine तीन प्रोटोकॉल पर आधारित है: Publisher (Output प्रकार के मान उत्सर्जित करता है, Failure प्रकार की त्रुटि के साथ विफल हो सकता है), Subscriber (मान प्राप्त करता है, Demand प्रबंधित करता है — अनुरोधित तत्वों की संख्या), Subscription (रद्द करने की क्षमता के साथ Publisher-Subscriber कनेक्शन का प्रतिनिधित्व करता है)। डेटा चैनल सब्सक्राइब पर आरंभ होता है और रद्द, पूर्ण या त्रुटि पर समाप्त होता है। Demand एक अद्वितीय Combine अवधारणा है: Subscriber Publisher को बताता है कि वह कितने तत्वों को संसाधित करने के लिए तैयार है, प्रोटोकॉल स्तर पर बैकप्रेशर लागू करता है।
Publisher दो संबद्ध प्रकारों वाला एक प्रोटोकॉल है: Output (उत्सर्जित मानों का प्रकार) और Failure (त्रुटि प्रकार जो Error को लागू करता है)। यदि स्ट्रीम विफल नहीं हो सकती है, तो Failure को Never के रूप में निर्दिष्ट किया जाता है — यह Subscriber को गारंटी देता है कि onReceive केवल Output के साथ कॉल किया जाएगा। अंतर्निहित Publishers में Just (एकल मान), Sequence (सरणी), URLSession.DataTaskPublisher (नेटवर्क अनुरोध), NotificationCenter.Publisher और @Published property wrapper शामिल हैं।
import Combine
// एक अनुक्रम से Publisher बनाना
let publisher = [1, 2, 3, 4, 5].publisher
// मान प्रसंस्करण के साथ Subscriber बनाना
class PrintSubscriber: Subscriber {
typealias Input = Int
typealias Failure = Never
func receive(subscription: Subscription) {
subscription.request(.unlimited)
}
func receive(_ input: Int) -> Subscribers.Demand {
print("Received: \(input)")
return .unlimited
}
func receive(completion: Subscribers.Completion<Never>) {
print("पूर्ण")
}
}
publisher.subscribe(PrintSubscriber())
Subscription एक प्रोटोकॉल है जो Publisher और Subscriber के बीच सक्रिय कनेक्शन का प्रतिनिधित्व करता है। Subscriber receive(subscription:) विधि में Subscription प्राप्त करता है और Demand निर्दिष्ट करने के लिए request(_:) कॉल करता है: .unlimited (सभी मान), .max(N) (सीमित संख्या) या .none (विराम)। Demand गतिशील रूप से बदल सकता है — Subscriber डेटा प्राप्ति के दौरान अनुरोधित तत्वों की संख्या बढ़ा या घटा सकता है। यह Publisher की ओर बफरिंग के बिना बैकप्रेशर प्रदान करता है।
Subject एक प्रकार है जो Publisher और Subscriber को जोड़ता है। Subject का उपयोग Publisher के रूप में (सब्सक्राइबर इसमें सब्सक्राइब करते हैं) और साथ ही Subscriber के रूप में (इसमें मान भेजे जाते हैं) किया जा सकता है। Combine दो प्रकार के Subject प्रदान करता है: PassthroughSubject (स्थिति संग्रहीत नहीं करता, केवल नए मान पास करता है) और CurrentValueSubject (वर्तमान मान संग्रहीत करता है और इसे नए सब्सक्राइबर को पास करता है)। Subject Combine रिएक्टिव चेन में इम्पेरेटिव कोड को एकीकृत करने के लिए आवश्यक है।
let subject = PassthroughSubject<String, Never>()
// Publisher के रूप में सदस्यता लेना
let cancellable = subject
.map { $0.uppercased() }
.sink { print($0) }
// Subscriber के रूप में मान भेजना
subject.send("hello") // "HELLO" प्रिंट करता है
subject.send("world") // "WORLD" प्रिंट करता है
CurrentValueSubject PassthroughSubject से एक प्रारंभिक मान और value प्रॉपर्टी होने में भिन्न है: एक सब्सक्राइबर सब्सक्रिप्शन पर तुरंत वर्तमान मान प्राप्त करता है, और फिर सभी बाद के अपडेट। CurrentValueSubject.value पढ़ने और लिखने योग्य है — value बदलना स्वचालित रूप से सभी सब्सक्राइबर को नया मान भेजता है। यह CurrentValueSubject को MVVM आर्किटेक्चर में स्थिति का प्रतिनिधित्व करने के लिए एक आदर्श विकल्प बनाता है: ViewModel CurrentValueSubject प्रकाशित करता है, View sink के माध्यम से परिवर्तनों के साथ सब्सक्राइब करता है।
दोनों Subject send(completion: .finished) या send(completion: .failure(error)) कॉल करके स्ट्रीम को समाप्त कर सकते हैं। समाप्ति के बाद, Subject इवेंट स्वीकार करना और उत्सर्जित करना बंद कर देता है। लंबे समय तक चलने वाली स्ट्रीम के लिए जो समाप्त नहीं होनी चाहिए (जैसे UI इवेंट), गलती से send(completion:) कॉल करने से बचने के लिए Never Failure के साथ PassthroughSubject का उपयोग करने की अनुशंसा की जाती है।
Combine ऑपरेटर Publisher विधियाँ हैं जो एक नया Publisher लौटाती हैं। प्रत्येक ऑपरेटर एक नया ऑब्जेक्ट बनाता है जो अपस्ट्रीम Publisher की सदस्यता लेता है और डाउनस्ट्रीम रूपांतरित मान उत्सर्जित करता है। चूंकि Publisher एक जेनेरिक प्रकार है, ऑपरेटर सख्त टाइपिंग बनाए रखते हैं: map Output<A> को Output<B> में बदलता है, tryMap त्रुटि की संभावना जोड़ता है। Combine में लगभग 100 अंतर्निहित ऑपरेटर हैं।
| श्रेणी | ऑपरेटर | उद्देश्य |
|---|---|---|
| रूपांतरण | map / tryMap / flatMap | मान या स्ट्रीम बदलना |
| फ़िल्टरिंग | filter / compactMap / removeDuplicates | मान चुनना या साफ करना |
| संयोजन | combineLatest / zip / merge | एकाधिक Publishers को जोड़ना |
| समय नियंत्रण | debounce / throttle / delay | इवेंट में देरी और थ्रॉटल |
| त्रुटि प्रबंधन | catch / retry / replaceError | Failure के बाद पुनर्प्राप्ति |
| Demand प्रबंधन | buffer / collect | समूहीकरण या बफरिंग |
flatMap Combine में RxSwift संस्करण से एक महत्वपूर्ण अंतर है: यह एक क्लोज़र स्वीकार करता है जो उसी Failure प्रकार के साथ एक Publisher लौटाता है और नेस्टेड Publisher को मुख्य स्ट्रीम में समतल करता है। maxPublishers: .max(1) के साथ flatMap switchMap की तरह व्यवहार करता है — जब कोई नया मान आता है तो पिछले नेस्टेड Publisher को रद्द कर देता है। यह खोज परिदृश्यों के लिए महत्वपूर्ण है: जब एक नया अक्षर टाइप किया जाता है, तो पिछला HTTP अनुरोध स्वचालित रूप से रद्द हो जाता है।
// पिछले अनुरोध को रद्द करने के साथ डिबाउंस खोज
searchTextField.textPublisher
.debounce(for: .seconds(0.3), scheduler: RunLoop.main)
.removeDuplicates()
.flatMap(maxPublishers: .max(1)) { query in
apiService.searchPublisher(query)
.catch { _ in Just([]) }
}
.receive(on: DispatchQueue.main)
.sink { results in
self.tableView.reloadData()
}
.store(in: &cancellables)
संयोजन ऑपरेटर — combineLatest और zip — RxSwift के समान काम करते हैं: combineLatest किसी भी Publisher के बदलने पर सभी Publishers के नवीनतम मानों का एक टपल उत्सर्जित करता है; zip मानों को इंडेक्स द्वारा जोड़ता है। merge एक ही प्रकार के Publishers को एक स्ट्रीम में जोड़ता है, क्रम संरक्षण की गारंटी नहीं है। Combine में select भी है — एक दुर्लभ ऑपरेटर जो कई में से पहला पूरा होने वाला Publisher चुनता है, और share — बिना पुन: निष्पादन के कई सब्सक्राइबर को स्ट्रीम का मल्टीकास्ट।
Scheduler Combine में एक प्रोटोकॉल है जो ऑपरेटरों के लिए निष्पादन संदर्भ को परिभाषित करता है। RxSwift के 5+ अंतर्निहित Schedulers के विपरीत, Combine मौजूदा Apple तंत्र का उपयोग करता है: DispatchQueue, RunLoop और OperationQueue। इनमें से प्रत्येक प्रकार Scheduler प्रोटोकॉल का अनुपालन करता है, जिससे उन्हें अतिरिक्त एडेप्टर के बिना सीधे receive(on:) और subscribe(on:) पर पास किया जा सकता है।
receive(on:) डाउनस्ट्रीम को निर्दिष्ट Scheduler पर स्विच करता है — RxSwift में observeOn के समतुल्य। receive(on:) के बाद सभी ऑपरेटर निर्दिष्ट Scheduler पर निष्पादित होते हैं। subscribe(on:) अपस्ट्रीम को स्विच करता है — Publisher निष्पादन को प्रभावित करता है। एक सामान्य पैटर्न: बैकग्राउंड कार्य के लिए subscribe(on: DispatchQueue.global()) और UI अपडेट के लिए receive(on: DispatchQueue.main)। SwiftUI में, .onReceive का उपयोग करते समय, मुख्य थ्रेड के लिए अंतर्निहित बाइंडिंग की आवश्यकता नहीं है, लेकिन sink के लिए स्पष्ट receive(on:).main की अनुशंसा की जाती है।
// पृष्ठभूमि लोडिंग + मुख्य थ्रेड पर UI
URLSession.shared.dataTaskPublisher(for: url)
.subscribe(on: DispatchQueue.global(qos: .background))
.tryMap { data, response -> Data in
guard let http = response as? HTTPURLResponse,
http.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
.receive(on: DispatchQueue.main)
.decode(type: User.self, decoder: JSONDecoder())
.sink(receiveCompletion: { print($0) },
receiveValue: { self.nameLabel.text = $0.name })
.store(in: &cancellables)
RunLoop.main UI संचालन के लिए DispatchQueue.main का एक विकल्प है। अंतर यह है कि RunLoop.main वर्तमान एप्लिकेशन इवेंट लूप से बंधा है, जबकि DispatchQueue.main मुख्य थ्रेड वैश्विक कतार से बंधा है। UIKit के लिए DispatchQueue.main की अनुशंसा की जाती है, SwiftUI के लिए — RunLoop.main। ImmediateWhenScheduler वर्तमान थ्रेड पर सिंक्रोनस रूप से संचालन निष्पादित करता है — परीक्षण और सरल Publishers के लिए डिफ़ॉल्ट रूप से उपयोग किया जाता है।
ObservableObject SwiftUI का एक प्रोटोकॉल है जो परिवर्तन प्रकाशित करने वाली वस्तुओं के लिए है। ObservableObject को लागू करने वाला एक वर्ग @Published property wrapper का उपयोग उन गुणों के लिए कर सकता है जिनके परिवर्तन स्वचालित रूप से SwiftUI को पुन: आरेखित करने की आवश्यकता के बारे में सूचित करते हैं। अंडर द हुड, @Published एक Publisher बनाता है जो wrappedValue बदलने पर objectWillChange Publisher को सूचित करता है। SwiftUI @StateObject, @ObservedObject या @EnvironmentObject के माध्यम से objectWillChange की सदस्यता लेता है।
@Published SwiftUI में Combine को एकीकृत करने का सबसे सामान्य तरीका है। जब @Published प्रॉपर्टी का मान बदलता है, SwiftAI उस ऑब्जेक्ट का उपयोग करने वाले सभी Views को अपडेट करता है। @StateObject एक ObservableObject इंस्टेंस बनाता है और उसके परिवर्तनों की सदस्यता लेता है। @StateObject के साथ बनाया गया View @Published गुण बदलने पर स्वचालित रूप से पुन: आरेखित होता है। यदि ऑब्जेक्ट को एकाधिक Views के बीच साझा करने की आवश्यकता है, तो @ObservedObject या @EnvironmentObject का उपयोग किया जाता है।
class UserViewModel: ObservableObject {
@Published var name: String = ""
@Published var age: Int = 0
private var cancellables = Set<AnyCancellable>()
init() {
$name
.debounce(for: .seconds(0.5), scheduler: RunLoop.main)
.sink { [weak self] newName in
AnalyticsService.logNameChange(newName)
}
.store(in: &cancellables)
}
}
struct UserView: View {
@StateObject var viewModel = UserViewModel()
var body: some View {
TextField("Name", text: $viewModel.name)
}
}
AnyCancellable Cancellable के लिए एक प्रकार-मिटाने वाला रैपर है जो सब्सक्रिप्शन रद्दीकरण टोकन संग्रहीत करता है। Set<AnyCancellable> सब्सक्रिप्शन के जीवनचक्र का प्रबंधन करता है: जब मालिक डीइनिशियलाइज़ होता है, तो सभी Cancellable स्वचालित रूप से रद्द हो जाते हैं। SwiftUI प्रोजेक्ट्स में, Set<AnyCancellable> ObservableObject वर्ग में घोषित किया जाता है, और सब्सक्रिप्शन .store(in: &cancellables) के माध्यम से जोड़े जाते हैं। UIKit के लिए, वही तंत्र UIViewController में &cancellables या मैन्युअल cancel() कॉल के माध्यम से भंडारण के साथ उपयोग किए जाते हैं।
Combine और RxSwift समान रिएक्टिव प्रोग्रामिंग कार्यों को हल करते हैं लेकिन इनमें मौलिक आर्किटेक्चरल अंतर हैं। Combine Apple SDK का हिस्सा है जिसमें iOS 13 तक बैकवर्ड संगतता है, RxSwift iOS 8+ का समर्थन करने वाली तृतीय-पक्ष लाइब्रेरी है। Combine Failure जेनेरिक के माध्यम से सख्त त्रुटि टाइपिंग का उपयोग करता है, RxSwift एकल Error प्रकार का उपयोग करता है। Combine प्लेटफ़ॉर्म स्तर पर SwiftUI के साथ एकीकृत है, RxSwift को UI एक्सटेंशन के लिए RxCocoa की आवश्यकता है।
Combine और RxSwift के बीच चुनाव प्रोजेक्ट की आवश्यकताओं पर निर्भर करता है। यदि न्यूनतम iOS संस्करण >= 13 है और प्रोजेक्ट SwiftUI का उपयोग करता है — Combine अंतर्निहित एकीकरण और कोई अतिरिक्त निर्भरता नहीं होने के कारण स्वाभाविक विकल्प है। यदि प्रोजेक्ट iOS 11-12 का समर्थन करता है, मौजूदा RxSwift कोडबेस शामिल है, या RxSwift में उपलब्ध विशिष्ट ऑपरेटरों की आवश्यकता है (जैसे Observable.from(path:)), — तो RxSwift एक मान्य समाधान बना रहता है।
| विशेषता | Combine | RxSwift |
|---|---|---|
| डेवलपर | Apple (SDK में निर्मित) | ReactiveX (समुदाय) |
| iOS संस्करण | iOS 13+ | iOS 8+ |
| त्रुटि प्रकार | जेनेरिक Failure (UI के लिए Never) | Error (कोई भी) |
| UI एकीकरण | @Published + SwiftUI | RxCocoa + UIKit |
| ऑपरेटर | ~100 अंतर्निहित | 400+ ऑपरेटर |
| Swift Concurrency | .values के माध्यम से (async अनुक्रम) | ब्रिज लाइब्रेरी के माध्यम से |
अक्सर पूछे जाने वाले प्रश्न
PassthroughSubject स्थिति संग्रहीत नहीं करता — सब्सक्राइबर को केवल सब्सक्रिप्शन के बाद भेजे गए इवेंट प्राप्त होते हैं। CurrentValueSubject वर्तमान मान संग्रहीत करता है और इसे प्रत्येक नए सब्सक्राइबर को सब्सक्रिप्शन पर तुरंत पास करता है। CurrentValueSubject स्थिति का प्रतिनिधित्व करने के लिए उपयुक्त है (जैसे isLoggedIn)।
एक सब्सक्रिप्शन AnyCancellable लौटाता है, जो cancel() कॉल करने या डीइनिशियलाइज़ेशन पर रद्द हो जाता है। समूह प्रबंधन के लिए Set<AnyCancellable> का उपयोग करें — सेट साफ़ होने पर सभी सब्सक्रिप्शन रद्द हो जाते हैं। यह RxSwift में DisposeBag के समान है।
हाँ, Combine स्ट्रीमिंग डेटा के लिए प्रासंगिक बना हुआ है: UI इवेंट, debounce, combineLatest, WebSocket। async/await एकल अनुरोधों के लिए सुविधाजनक है, Combine — निरंतर या एकाधिक स्ट्रीम के लिए। दोनों फ्रेमवर्क पूरक हैं — Publisher को AsyncSequence में परिवर्तित किया जा सकता है।
UIKit में अंतर्निहित Publishers नहीं हैं, लेकिन Apple एक्सटेंशन प्रदान करता है: NotificationCenter.default.publisher(for:), Timer.publish, URLSession.dataTaskPublisher। कस्टम UI इवेंट के लिए, Future या Subject के माध्यम से PassthroughSubject या @IBAction का उपयोग Publisher में लपेटकर किया जाता है।
बैकप्रेशर प्रवाह दर को नियंत्रित करने का एक तंत्र है: Subscriber Demand के माध्यम से Publisher को बताता है कि वह कितने तत्वों को संसाधित करने के लिए तैयार है। यदि Demand = .max(1) है, तो Publisher अगला मान भेजने से पहले अनुरोध की प्रतीक्षा करता है। यह उत्पादक और उपभोक्ता गति के बेमेल होने पर बफ़र ओवरफ़्लो को रोकता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें