Combine — Apple tərəfindən iOS 13, macOS Catalina, tvOS 13 və watchOS 6-da təqdim edilən native reaktiv proqramlaşdırma freymvorkudur. Publisher və Subscriber nümunəsi vasitəsilə asinxron hadisələrin işlənməsi üçün deklarativ Swift API təqdim edir, delegatları, closure-ları və NotificationCenter-i vahid zəncirlə əvəz edir. Apple, 2025-ə görə, Combine SwiftUI və müasir iOS arxitekturaları üçün təməldir, async/await və Structured Concurrency ilə sıx əlaqədə işləyir. Freymvork asinxron əməliyyatların kompozisiyası üçün thread təhlükəsizliyi təminatı ilə dizayn edilmişdir.
Əsas məqamlar
Combine — Apple SDK-sına daxil edilmiş deklarativ reaktiv proqramlaşdırma freymvorkudur. O, Reactive Streams nümunəsini tətbiq edir: Publisher dəyərlər istehsal edir, Subscriber onları istehlak edir, operatorlar isə axını onların arasında çevirir. Combine callback və delegat problemlərini həll edir, şəbəkə cavablarından UI dəyişikliklərinə qədər istənilən asinxron hadisələr üçün vahid kompozisiya modeli təqdim edir.
Combine-in yaranmasından əvvəl iOS tərtibatçıları üçüncü tərəf kitabxanalarından, ilk növbədə RxSwift-dən istifadə edirdilər. Apple Combine-i ekosistemə dərin inteqrasiya ilə native alternativ olaraq yaratdı: freymvork @objc körpüləri vasitəsilə Objective-C-ni dəstəkləyir, KVO (NSObject.keyValuePublisher vasitəsilə Key-Value Observing) və NotificationCenter ilə işləyir, həmçinin SwiftUI üçün əsasdır. SwiftUI-də dərc edilmiş bütün UIKit komponentləri görünüşləri yeniləmək üçün Combine-dən istifadə edir.
Combine Swift Concurrency nəzərə alınmaqla dizayn edilmişdir: iOS 15-dən etibarən Publisher .values vasitəsilə AsyncSequence-ə çevrilə bilər və for-await-in dövrlərində istifadə edilə bilər. Async funksiyalarının Publisher-ə tərs çevrilməsi Future vasitəsilə həyata keçirilir. Apple WWDC 2024-ə görə, Combine tək asinxron çağırışlar üçün async/await-in yaranmasına baxmayaraq, UIKit tətbiqlərində axın məlumatlarının işlənməsi üçün tövsiyə olunan freymvork olaraq qalır.
Combine üç protokola əsaslanır: Publisher (Output tipli dəyərlər göndərir, Failure tipli xəta ilə başa çata bilər), Subscriber (dəyərləri alır, Demand-i idarə edir — tələb olunan elementlərin sayı), Subscription (ləğv etmə imkanı ilə Publisher-Subscriber əlaqəsini təmsil edir). Məlumat ötürmə kanalı subscribe ilə başladılır və cancel, completion və ya error ilə başa çatır. Demand — Combine-in unikal konsepsiyası: Subscriber Publisher-ə neçə elementi emal etməyə hazır olduğunu bildirir, protokol səviyyəsində backpressure tətbiq edir.
Publisher — iki əlaqəli tipi olan protokoldur: Output (göndərilən dəyərlərin tipi) və Failure (Error-u tətbiq edən xəta tipi). Axın xəta ilə başa çata bilmirsə, Failure Never olaraq göstərilir — bu, Subscriber-ə onReceive-nin yalnız Output ilə çağırılacağına zəmanət verir. Daxili Publisher-lərə Just (bir dəyər), Sequence (massiv), URLSession.DataTaskPublisher (şəbəkə sorğusu), NotificationCenter.Publisher və @Published property wrapper daxildir.
import Combine
// Ardıcıllıqdan Publisher yaradın
let publisher = [1, 2, 3, 4, 5].publisher
// Dəyərlərin işlənməsi ilə Subscriber yaradın
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("Tamamlandı")
}
}
publisher.subscribe(PrintSubscriber())
Subscription — Publisher və Subscriber arasında aktiv əlaqəni təmsil edən protokoldur. Subscriber Subscription-ı receive(subscription:) metodunda alır və Demand-i göstərmək üçün request(_:) çağırır: .unlimited (bütün dəyərlər), .max(N) (məhdud sayda) və ya .none (fasilə). Demand dinamik olaraq dəyişə bilər — Subscriber məlumat qəbulu prosesində tələb olunan elementlərin sayını artıra və ya azalda bilər. Bu, Publisher tərəfində buferləşdirmə olmadan backpressure təmin edir.
Subject — Publisher və Subscriber-i birləşdirən tipdir. Subject Publisher kimi (ona abunə olmaq olar) və eyni zamanda Subscriber kimi (ona dəyərlər göndərmək olar) istifadə edilə bilər. Combine iki növ Subject təqdim edir: PassthroughSubject (vəziyyəti saxlamır, yalnız yeni dəyərləri ötürür) və CurrentValueSubject (cari dəyəri saxlayır və onu yeni abunəçilərə ötürür). Subject imperativ kodu reaktiv Combine zəncirlərinə inteqrasiya etmək üçün lazımdır.
let subject = PassthroughSubject<String, Never>()
// Publisher kimi abunəlik
let cancellable = subject
.map { $0.uppercased() }
.sink { print($0) }
// Subscriber kimi dəyərlərin göndərilməsi
subject.send("hello") // "HELLO" çap edir
subject.send("dünya") // "WORLD" çap edir
CurrentValueSubject PassthroughSubject-dən ilkin dəyərin və value xüsusiyyətinin olması ilə fərqlənir: abunəçi abunə olduqda dərhal cari dəyəri, sonra isə bütün sonrakı yeniləmələri alır. CurrentValueSubject.value oxumaq və yazmaq üçün əlçatandır — value-nun dəyişdirilməsi avtomatik olaraq bütün abunəçilərə yeni dəyər göndərir. Bu, CurrentValueSubject-i MVVM arxitekturasında vəziyyəti təmsil etmək üçün ideal seçim edir: ViewModel CurrentValueSubject dərc edir, View dəyişikliklərlə sink vasitəsilə abunə olur.
Hər iki Subject axını send(completion: .finished) və ya send(completion: .failure(error)) çağırışı ilə başa çatdırmağa imkan verir. Başa çatdıqdan sonra Subject hadisələri qəbul etməyi və ötürməyi dayandırır. Bitməməli olan uzunmüddətli axınlar (məsələn, UI hadisələri) üçün təsadüfi send(completion:) çağırışını istisna etmək üçün Never Failure ilə PassthroughSubject istifadə etmək tövsiyə olunur.
Operatorlar Combine — yeni Publisher qaytaran Publisher metodlarıdır. Hər bir operator upstream Publisher-ə abunə olan və çevrilmiş dəyərləri downstream-ə göndərən yeni obyekt yaradır. Publisher generic tip olduğundan, operatorlar ciddi tipizasiyanı qoruyur: map Output<A>-nı Output<B>-yə çevirir, tryMap xəta ehtimalı əlavə edir. Combine təxminən 100 daxili operatordan ibarətdir.
| Kateqoriya | Operator | Məqsəd |
|---|---|---|
| Çevirmə | map / tryMap / flatMap | Dəyərlərin və ya axınların çevrilməsi |
| Filtrləmə | filter / compactMap / removeDuplicates | Dəyərlərin seçilməsi və ya təmizlənməsi |
| Birləşdirmə | combineLatest / zip / merge | Bir neçə Publisher-in birləşdirilməsi |
| Vaxt idarəetməsi | debounce / throttle / delay | Hadisələrin gecikdirilməsi və seyreltilməsi |
| Xəta idarəetməsi | catch / retry / replaceError | Failure-dən sonra bərpa |
| Demand idarəetməsi | buffer / collect | Qruplaşdırma və ya buferləşdirmə |
flatMap Combine-də RxSwift versiyasından əhəmiyyətli fərqə malikdir: eyni Failure tipinə malik Publisher qaytaran closure qəbul edir və iç-içə Publisher-i əsas axına açır. maxPublishers: .max(1) ilə flatMap switchMap kimi davranır — yeni dəyər gəldikdə əvvəlki iç-içə Publisher-i ləğv edir. Bu, axtarış ssenariləri üçün kritikdir: yeni simvol daxil edildikdə əvvəlki HTTP sorğusu avtomatik ləğv edilir.
// Əvvəlki sorğunun ləğvi ilə debounce axtarış
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)
Birləşdirmə operatorları — combineLatest və zip — RxSwift-də olduğu kimi işləyir: combineLatest hər hansı bir Publisher dəyişdikdə bütün Publisher-lərin son dəyərlərinin kortejini göndərir; zip dəyərləri indeksə görə cüt-cüt birləşdirir. merge eyni tipdəki Publisher-ləri bir axına birləşdirir, preserveOrder təmin edilmir. Combine-də həmçinin select — bir neçə arasından ilk başa çatan Publisher-i seçən nadir operator, və share — axını təkrar icra etmədən çoxlu abunəçiyə multicast edən operator mövcuddur.
Scheduler Combine-də — operatorlar üçün icra kontekstini təyin edən protokoldur. RxSwift-in 5+ daxili Scheduler-indən fərqli olaraq, Combine mövcud Apple mexanizmlərindən istifadə edir: DispatchQueue, RunLoop və OperationQueue. Bu tiplərin hər biri Scheduler protokoluna uyğundur, bu da onları əlavə adapterlər olmadan birbaşa receive(on:) və subscribe(on:)-a ötürməyə imkan verir.
receive(on:) downstream-i müəyyən edilmiş Scheduler-ə keçirir — RxSwift-də observeOn-un ekvivalenti. receive(on:)-dan sonrakı bütün operatorlar müəyyən edilmiş Scheduler-də icra olunur. subscribe(on:) upstream-i keçirir — Publisher-in icrasına təsir göstərir. Tipik nümunə: fon işi üçün subscribe(on: DispatchQueue.global()) və UI yeniləməsi üçün receive(on: DispatchQueue.main). SwiftUI-də .onReceive istifadə edərkən əsas thread-ə daxili bağlantı tələb olunmur, lakin sink üçün açıq receive(on:).main tövsiyə olunur.
// Fon yükləmə + əsas thread-də 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 əməliyyatları üçün DispatchQueue.main-ə alternativdir. Fərq ondadır ki, RunLoop.main tətbiqin cari hadisə dövrünə bağlıdır, DispatchQueue.main isə əsas thread-in qlobal növbəsinə. UIKit üçün DispatchQueue.main, SwiftUI üçün RunLoop.main tövsiyə olunur. ImmediateWhenScheduler əməliyyatları cari thread-də sinxron icra edir — testlər və sadə Publisher-lər üçün default olaraq istifadə olunur.
ObservableObject — dəyişikliklər dərc edən obyektlər üçün SwiftUI protokoludur. ObservableObject-u tətbiq edən sinif @Published property wrapper-indan istifadə edə bilər, dəyişiklikləri avtomatik olaraq SwiftUI-yə yenidən çəkmə ehtiyacı barədə məlumat verir. @Published altlıqda Publisher yaradır, wrappedValue dəyişdikdə objectWillChange Publisher-inə məlumat verir. SwiftUI @StateObject, @ObservedObject və ya @EnvironmentObject vasitəsilə objectWillChange-ə abunə olur.
@Published — Combine-i SwiftUI-də inteqrasiya etməyin ən geniş yayılmış üsuludur. @Published xüsusiyyətinin dəyəri dəyişdikdə, SwiftUI bu obyektdən istifadə edən bütün View-ları yeniləyir. @StateObject ObservableObject nümunəsi yaradır və onun dəyişikliklərinə abunə olur. @StateObject ilə yaradılmış View @Published xüsusiyyətləri dəyişdikdə avtomatik olaraq yenidən çəkilir. Obyekt çoxsaylı View-lar arasında ötürülməlidirsə, @ObservedObject və ya @EnvironmentObject istifadə olunur.
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 üçün tip silici, abunəliyin ləğv tokenini saxlayır. Set<AnyCancellable> abunəliklərin həyat dövrünü idarə edir: sahibinin deinicializasiyası zamanı bütün Cancellable-lar avtomatik ləğv edilir. SwiftUI layihələrində Set<AnyCancellable> ObservableObject sinfində elan edilir, abunəliklər isə .store(in: &cancellables) vasitəsilə əlavə olunur. UIKit üçün eyni mexanizmlər UIViewController-də &cancellables vasitəsilə saxlama və ya əl ilə cancel() çağırışı ilə istifadə olunur.
Combine və RxSwift eyni reaktiv proqramlaşdırma vəzifələrini həll edir, lakin fundamental arxitektura fərqlərinə malikdir. Combine — iOS 13-ə qədər geriyə uyğunluqla Apple SDK-nın bir hissəsi, RxSwift — iOS 8+ dəstəyi ilə üçüncü tərəf kitabxanası. Combine Failure generic vasitəsilə ciddi xəta tipizasiyasından istifadə edir, RxSwift — vahid Error tipindən. Combine platforma səviyyəsində SwiftUI ilə inteqrasiya olunub, RxSwift UI genişləndirmələri üçün RxCocoa tələb edir.
Combine və RxSwift arasında seçim layihə tələblərindən asılıdır. Minimal iOS versiyası >= 13 və layihə SwiftUI istifadə edirsə — Combine daxili inteqrasiya və əlavə asılılıqların olmaması səbəbindən təbii seçimdir. Layihə iOS 11-12-ni dəstəkləyirsə, mövcud RxSwift kod bazasına malikdirsə və ya yalnız RxSwift-də mövcud olan spesifik operatorlar tələb edirsə (məsələn, Observable.from(path:)), — RxSwift əsaslandırılmış həll olaraq qalır.
| Xüsusiyyət | Combine | RxSwift |
|---|---|---|
| Yaradıcı | Apple (SDK-ya daxildir) | ReactiveX (icma) |
| iOS versiyası | iOS 13+ | iOS 8+ |
| Xəta tipi | Generic Failure (UI üçün Never) | Error (istənilən) |
| UI inteqrasiyası | @Published + SwiftUI | RxCocoa + UIKit |
| Operatorlar | ~100 daxili | 400+ operator |
| Swift Concurrency | .values vasitəsilə (async sequence) | Körpü kitabxanası vasitəsilə |
Tez-tez verilən suallar
PassthroughSubject vəziyyəti saxlamır — abunəçi yalnız abunəlikdən sonra göndərilmiş hadisələri alır. CurrentValueSubject cari dəyəri saxlayır və onu hər bir yeni abunəçiyə abunə olduqda dərhal ötürür. CurrentValueSubject vəziyyəti təmsil etmək üçün uyğundur (məsələn, isLoggedIn).
Abunəlik AnyCancellable qaytarır, o, cancel() çağırıldıqda və ya deinicializasiya zamanı ləğv edilir. Qrup idarəetməsi üçün Set<AnyCancellable> istifadə edin — set təmizləndikdə bütün abunəliklər ləğv edilir. Bu, RxSwift-də DisposeBag-in analoqudur.
Bəli, Combine axın məlumatları üçün aktual olaraq qalır: UI hadisələri, debounce, combineLatest, WebSocket. async/await tək sorğular üçün əlverişlidir, Combine — davamlı və ya çoxsaylı axınlar üçün. Hər iki freymvork bir-birini tamamlayır — Publisher AsyncSequence-ə çevrilə bilər.
UIKit-in daxili Publisher-ləri yoxdur, lakin Apple genişləndirmələr təqdim edir: NotificationCenter.default.publisher(for:), Timer.publish, URLSession.dataTaskPublisher. Xüsusi UI hadisələri üçün PassthroughSubject və ya Future və ya Subject vasitəsilə Publisher-ə bükülmüş @IBAction istifadə olunur.
Backpressure — axın sürətini idarəetmə mexanizmidir: Subscriber Demand vasitəsilə Publisher-ə neçə elementi emal etməyə hazır olduğunu bildirir. Demand = .max(1) olarsa, Publisher növbəti dəyəri göndərməzdən əvvəl sorğu gözləyir. Bu, istehsalçı və istehlakçı sürətləri uyğunsuzluğunda buferin daşmasının qarşısını alır.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun