Combine — bu Apple tomonidan iOS 13, macOS Catalina, tvOS 13 va watchOS 6 da taqdim etilgan mahalliy reaktiv dasturlash freymvorkidir. U Publisher va Subscriber namunasi orqali asinxron hodisalarni qayta ishlash uchun deklarativ Swift API ni taqdim etadi, delegatlar, yopilishlar va NotificationCenter ni yagona zanjir bilan almashtiradi. Apple, 2025 ma'lumotlariga ko'ra, Combine SwiftUI va zamonaviy iOS arxitekturalari uchun asos bo'lib, async/await va Structured Concurrency bilan chambarchas bog'liq holda ishlaydi. Freymvork ip xavfsizligi kafolatlari bilan asinxron operatsiyalarni kompozitsiya qilish uchun mo'ljallangan.
Asosiy fikrlar
Combine — bu Apple SDK ga o'rnatilgan deklarativ reaktiv dasturlash freymvorkidir. U Reactive Streams namunasini amalga oshiradi: Publisher qiymatlarni ishlab chiqaradi, Subscriber ularni iste'mol qiladi va operatorlar oqimni ular o'rtasida o'zgartiradi. Combine callback va delegat muammosini hal qiladi, tarmoq javoblaridan UI o'zgarishlarigacha bo'lgan har qanday asinxron hodisalar uchun yagona kompozitsiya modelini taqdim etadi.
Combine paydo bo'lishidan oldin iOS dasturchilari uchinchi tomon kutubxonalaridan, birinchi navbatda RxSwift dan foydalanganlar. Apple Combine ni ekotizimga chuqur integratsiya bilan mahalliy muqobil sifatida yaratdi: freymvork @objc ko'priklari orqali Objective-C ni qo'llab-quvvatlaydi, KVO (NSObject.keyValuePublisher orqali Key-Value Observing) va NotificationCenter bilan ishlaydi, shuningdek SwiftUI uchun asosdir. SwiftUI da nashr etilgan barcha UIKit komponentlari ko'rinishlarni yangilash uchun Combine dan foydalanadi.
Combine Swift Concurrency ni hisobga olgan holda ishlab chiqilgan: iOS 15 dan boshlab Publisher .values orqali AsyncSequence ga aylantirilishi va for-await-in sikllarida ishlatilishi mumkin. Async funksiyalarining Publisher ga teskari aylantirilishi Future orqali amalga oshiriladi. Apple WWDC 2024 ma'lumotlariga ko'ra, Combine yagona asinxron chaqiruvlar uchun async/await paydo bo'lishiga qaramay, UIKit ilovalarida oqim ma'lumotlarini qayta ishlash uchun tavsiya etilgan freymvork bo'lib qolmoqda.
Combine uch protokolga asoslanadi: Publisher (Output tipidagi qiymatlarni chiqaradi, Failure tipidagi xato bilan tugashi mumkin), Subscriber (qiymatlarni oladi, Demand ni boshqaradi — so'ralgan elementlar soni), Subscription (bekor qilish imkoniyati bilan Publisher-Subscriber aloqasini ifodalaydi). Ma'lumot uzatish kanali subscribe da ishga tushiriladi va cancel, completion yoki error da tugaydi. Demand — Combine ning noyob kontseptsiyasi: Subscriber Publisher ga nechta elementni qayta ishlashga tayyorligini bildiradi, protokol darajasida backpressure ni amalga oshiradi.
Publisher — ikkita bog'liq turga ega protokol: Output (chiqarilgan qiymatlar turi) va Failure (Error ni amalga oshiradigan xato turi). Agar oqim xato bilan tugamasa, Failure Never sifatida ko'rsatiladi — bu Subscriber ga onReceive faqat Output bilan chaqirilishini kafolatlaydi. O'rnatilgan Publisher larga Just (bitta qiymat), Sequence (massiv), URLSession.DataTaskPublisher (tarmoq so'rovi), NotificationCenter.Publisher va @Published property wrapper kiradi.
import Combine
// Ketma-ketlikdan Publisher yaratish
let publisher = [1, 2, 3, 4, 5].publisher
// Qiymatlarni qayta ishlash bilan Subscriber yaratish
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("Tugallandi")
}
}
publisher.subscribe(PrintSubscriber())
Subscription — bu Publisher va Subscriber o'rtasidagi faol aloqani ifodalovchi protokol. Subscriber Subscription ni receive(subscription:) metodida oladi va Demand ni ko'rsatish uchun request(_:) ni chaqiradi: .unlimited (barcha qiymatlar), .max(N) (cheklangan son) yoki .none (pauza). Demand dinamik o'zgarishi mumkin — Subscriber ma'lumot olish jarayonida so'ralgan elementlar sonini oshirishi yoki kamaytirishi mumkin. Bu Publisher tomonda buferlashsiz backpressure ni ta'minlaydi.
Subject — bu Publisher va Subscriber ni birlashtiruvchi turdir. Subject Publisher sifatida (unga obuna bo'lish mumkin) va bir vaqtning o'zida Subscriber sifatida (unga qiymatlar yuborish mumkin) ishlatilishi mumkin. Combine ikki turdagi Subject ni taqdim etadi: PassthroughSubject (holatni saqlamaydi, faqat yangi qiymatlarni uzatadi) va CurrentValueSubject (joriy qiymatni saqlaydi va uni yangi obunachilarga uzatadi). Subject imperativ kodni reaktiv Combine zanjirlariga integratsiya qilish uchun zarur.
let subject = PassthroughSubject<String, Never>()
// Publisher sifatida obuna
let cancellable = subject
.map { $0.uppercased() }
.sink { print($0) }
// Subscriber sifatida qiymatlarni yuborish
subject.send("hello") // "HELLO" chop etadi
subject.send("dunyo") // "WORLD" chop etadi
CurrentValueSubject PassthroughSubject dan boshlang'ich qiymat va value xususiyatining mavjudligi bilan farq qiladi: obunachi obuna bo'lganda darhol joriy qiymatni, keyin esa barcha keyingi yangilanishlarni oladi. CurrentValueSubject.value o'qish va yozish uchun mavjud — value ning o'zgarishi avtomatik ravishda barcha obunachilarga yangi qiymatni yuboradi. Bu CurrentValueSubject ni MVVM arxitekturasida holatni ifodalash uchun ideal tanlovga aylantiradi: ViewModel CurrentValueSubject ni nashr etadi, View o'zgarishlar bilan sink orqali obuna bo'ladi.
Ikkala Subject ham oqimni send(completion: .finished) yoki send(completion: .failure(error)) chaqiruvi bilan tugatishga imkon beradi. Tugatilgandan so'ng, Subject hodisalarni qabul qilish va uzatishni to'xtatadi. Tugamasligi kerak bo'lgan uzoq muddatli oqimlar (masalan, UI hodisalari) uchun tasodifiy send(completion:) chaqiruvini istisno qilish uchun Never Failure bilan PassthroughSubject dan foydalanish tavsiya etiladi.
Operatorlar Combine — yangi Publisher qaytaradigan Publisher metodlaridir. Har bir operator yuqori oqim Publisher ga obuna bo'ladigan va o'zgartirilgan qiymatlarni quyi oqimga chiqaradigan yangi ob'ekt yaratadi. Publisher generic tur bo'lgani uchun operatorlar qat'iy tipizatsiyani saqlaydi: map Output<A> ni Output<B> ga o'zgartiradi, tryMap xato ehtimolini qo'shadi. Combine taxminan 100 ta o'rnatilgan operatordan iborat.
| Kategoriya | Operator | Maqsad |
|---|---|---|
| O'zgartirish | map / tryMap / flatMap | Qiymatlar yoki oqimlarni o'zgartirish |
| Filtrlash | filter / compactMap / removeDuplicates | Qiymatlarni tanlash yoki tozalash |
| Birlashtirish | combineLatest / zip / merge | Bir nechta Publisher larni birlashtirish |
| Vaqt boshqaruvi | debounce / throttle / delay | Hodisalarni kechiktirish va siyraklash |
| Xato boshqaruvi | catch / retry / replaceError | Failure dan keyin tiklanish |
| Demand boshqaruvi | buffer / collect | Guruhlash yoki buferlash |
flatMap Combine da RxSwift versiyasidan muhim farqga ega: bir xil Failure turiga ega Publisher qaytaradigan closure ni qabul qiladi va ichki Publisher ni asosiy oqimga ochadi. maxPublishers: .max(1) bilan flatMap switchMap kabi harakat qiladi — yangi qiymat kelganda oldingi ichki Publisher ni bekor qiladi. Bu qidiruv stsenariylari uchun juda muhim: yangi belgi kiritilganda oldingi HTTP so'rovi avtomatik ravishda bekor qilinadi.
// Oldingi so'rovni bekor qilish bilan debounce qidiruv
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)
Birlashtirish operatorlari — combineLatest va zip — RxSwift dagi kabi ishlaydi: combineLatest har qanday Publisher o'zgarganda barcha Publisher larning oxirgi qiymatlari kortejini chiqaradi; zip qiymatlarni indeks bo'yicha juft-juft birlashtiradi. merge bir xil turdagi Publisher larni bitta oqimga birlashtiradi, preserveOrder kafolatlanmaydi. Combine da shuningdek select — bir nechtadan birinchi tugagan Publisher ni tanlaydigan noyob operator, va share — oqimni qayta bajarmasdan ko'plab obunachilarga multicast qiluvchi operator mavjud.
Scheduler Combine da — operatorlar uchun bajarish kontekstini belgilaydigan protokoldir. RxSwift ning 5+ o'rnatilgan Scheduler laridan farqli o'laroq, Combine mavjud Apple mexanizmlaridan foydalanadi: DispatchQueue, RunLoop va OperationQueue. Bu turlarning har biri Scheduler protokoliga mos keladi, bu ularni qo'shimcha adapterlarsiz to'g'ridan-to'g'ri receive(on:) va subscribe(on:) ga uzatish imkonini beradi.
receive(on:) quyi oqimni belgilangan Scheduler ga o'tkazadi — RxSwift dagi observeOn ning ekvivalenti. receive(on:) dan keyingi barcha operatorlar belgilangan Scheduler da bajariladi. subscribe(on:) yuqori oqimni o'tkazadi — Publisher ning bajarilishiga ta'sir qiladi. Odatiy namuna: fon ishi uchun subscribe(on: DispatchQueue.global()) va UI yangilash uchun receive(on: DispatchQueue.main). SwiftUI da .onReceive ishlatganda asosiy ipga o'rnatilgan bog'lanish talab qilinmaydi, lekin sink uchun aniq receive(on:).main tavsiya etiladi.
// Fon yuklash + asosiy ipda 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 operatsiyalari uchun DispatchQueue.main ga alternativdir. Farq shundaki, RunLoop.main ilovaning joriy hodisa sikliga bog'langan, DispatchQueue.main esa asosiy ipning global navbatiga. UIKit uchun DispatchQueue.main, SwiftUI uchun RunLoop.main tavsiya etiladi. ImmediateWhenScheduler operatsiyalarni joriy ipda sinxron bajaradi — testlar va oddiy Publisher lar uchun sukut bo'yicha ishlatiladi.
ObservableObject — o'zgarishlarni nashr etadigan ob'ektlar uchun SwiftUI protokolidir. ObservableObject ni amalga oshiradigan sinf @Published property wrapper indan o'zgarishlari avtomatik ravishda SwiftUI ni qayta chizish zarurati haqida xabardor qiladigan xususiyatlar uchun foydalanishi mumkin. @Published ostida wrappedValue o'zgarganda objectWillChange Publisher ini xabardor qiladigan Publisher yaratadi. SwiftUI @StateObject, @ObservedObject yoki @EnvironmentObject orqali objectWillChange ga obuna bo'ladi.
@Published — Combine ni SwiftUI da integratsiya qilishning eng keng tarqalgan usuli. @Published xususiyatining qiymati o'zgarganda, SwiftUI ushbu ob'ektdan foydalanadigan barcha View larni yangilaydi. @StateObject ObservableObject namunasini yaratadi va uning o'zgarishlariga obuna bo'ladi. @StateObject bilan yaratilgan View @Published xususiyatlari o'zgarganda avtomatik ravishda qayta chiziladi. Agar ob'ekt bir nechta View lar o'rtasida uzatilishi kerak bo'lsa, @ObservedObject yoki @EnvironmentObject ishlatiladi.
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 uchun tur tozalagich, obunani bekor qilish tokenini saqlaydi. Set<AnyCancellable> obunalarning hayot aylanishini boshqaradi: egasining deinitsializatsiyasida barcha Cancellable lar avtomatik ravishda bekor qilinadi. SwiftUI loyihalarida Set<AnyCancellable> ObservableObject sinfida e'lon qilinadi, obunalar esa .store(in: &cancellables) orqali qo'shiladi. UIKit uchun UIViewController da &cancellables orqali saqlash yoki qo'lda cancel() chaqiruvi bilan bir xil mexanizmlar qo'llaniladi.
Combine va RxSwift bir xil reaktiv dasturlash vazifalarini hal qiladi, ammo fundamental arxitektura farqlariga ega. Combine — iOS 13 gacha orqaga moslik bilan Apple SDK ning bir qismi, RxSwift — iOS 8+ qo'llab-quvvatlashi bilan uchinchi tomon kutubxonasi. Combine Failure generic orqali qat'iy xato tipizatsiyasidan foydalanadi, RxSwift — yagona Error tipidan. Combine platforma darajasida SwiftUI bilan integratsiyalangan, RxSwift UI kengaytmalari uchun RxCocoa talab qiladi.
Combine va RxSwift o'rtasidagi tanlov loyiha talablariga bog'liq. Agar minimal iOS versiyasi >= 13 va loyiha SwiftUI dan foydalansa — Combine o'rnatilgan integratsiya va qo'shimcha bog'liqliklarning yo'qligi tufayli tabiiy tanlovdir. Agar loyiha iOS 11-12 ni qo'llab-quvvatlasa, mavjud RxSwift kod bazasiga ega bo'lsa yoki faqat RxSwift da mavjud bo'lgan maxsus operatorlarni talab qilsa (masalan, Observable.from(path:)), — RxSwift asosli yechim bo'lib qoladi.
| Xususiyat | Combine | RxSwift |
|---|---|---|
| Yaratuvchi | Apple (SDK ga o'rnatilgan) | ReactiveX (jamoa) |
| iOS versiyasi | iOS 13+ | iOS 8+ |
| Xato turi | Generic Failure (UI uchun Never) | Error (har qanday) |
| UI integratsiyasi | @Published + SwiftUI | RxCocoa + UIKit |
| Operatorlar | ~100 o'rnatilgan | 400+ operator |
| Swift Concurrency | .values orqali (async sequence) | Ko'prik kutubxonasi orqali |
Tez-tez beriladigan savollar
PassthroughSubject holatni saqlamaydi — obunachi faqat obunadan keyin yuborilgan hodisalarni oladi. CurrentValueSubject joriy qiymatni saqlaydi va uni har bir yangi obunachiga obuna bo'lganda darhol uzatadi. CurrentValueSubject holatni ifodalash uchun mos keladi (masalan, isLoggedIn).
Obuna AnyCancellable qaytaradi, u cancel() chaqirilganda yoki deinitsializatsiyada bekor qilinadi. Guruh boshqaruvi uchun Set<AnyCancellable> dan foydalaning — set tozalanganda barcha obunalar bekor qilinadi. Bu RxSwift dagi DisposeBag ning analogidir.
Ha, Combine oqim ma'lumotlari uchun dolzarb bo'lib qolmoqda: UI hodisalari, debounce, combineLatest, WebSocket. async/await yagona so'rovlar uchun qulay, Combine — uzluksiz yoki bir nechta oqimlar uchun. Ikkala freymvork bir-birini to'ldiradi — Publisher AsyncSequence ga aylantirilishi mumkin.
UIKit o'rnatilgan Publisher larga ega emas, ammo Apple kengaytmalarni taqdim etadi: NotificationCenter.default.publisher(for:), Timer.publish, URLSession.dataTaskPublisher. Maxsus UI hodisalari uchun Future yoki Subject orqali Publisher ga o'ralgan PassthroughSubject yoki @IBAction ishlatiladi.
Backpressure — oqim tezligini boshqarish mexanizmi: Subscriber Demand orqali Publisher ga nechta elementni qayta ishlashga tayyorligini bildiradi. Agar Demand = .max(1) bo'lsa, Publisher keyingi qiymatni yuborishdan oldin so'rovni kutadi. Bu ishlab chiqaruvchi va iste'molchi tezliklari mos kelmasligida buferning to'lib ketishining oldini oladi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.