Combine je framework reaktivního programování od Apple, představený v iOS 13. Podle Apple Documentation, 2025 poskytuje Combine jednotné deklarativní API pro zpracování asynchronních událostí. Publisher určuje zdroj dat a Subscriber se přihlašuje k jejich odběru.
Hlavní
Combine je deklarativní Swift framework pro zpracování asynchronních událostí v čase. Na rozdíl od přístupů založených na callback, Combine umožňuje popisovat datové pipeline pomocí řetězce operátorů. Framework je integrován s Foundation (URLSession, Timer, NotificationCenter) a SwiftUI (ObservableObject, @Published).
Každý typ implementující protokol Publisher musí definovat Output (typ hodnot) a Failure (typ chyby). Publisher není aktivní do přihlášení — začíná emitovat události až po volání subscribe. To je studená sémantika, charakteristická pro reaktivní streamy, zvyšující efektivitu.
Subscriber přijímá události prostřednictvím tří metod: receive(subscription:) — potvrzení přihlášení se správou demand; receive(_:) — přijetí nové hodnoty; receive(completion:) — dokončení toku s úspěchem nebo chybou. Demand určuje počet hodnot, které je Subscriber připraven přijmout — to je mechanismus backpressure.
Apple poskytuje mnoho vestavěných Publisher: Just emituje jednu hodnotu a končí, Future — asynchronní výsledek s uzávěrem, Deferred — odložené vytvoření Publisher až do okamžiku přihlášení. URLSession.dataTaskPublisher převádí síťový požadavek na reaktivní tok. Timer.publish vytváří periodický časovač. NotificationCenter.default.publisher přeměňuje oznámení na Publisher. Tyto integrace umožňují přihlásit se k událostem bez ručního mostu.
V Combine jsou Publisher a Subscriber propojeny protokolem Subscription. Subscription je spojovací objekt, který řídí tok dat. Vývojář nemusí vytvářet vlastní typy Publisher — Apple poskytuje vestavěné: Just, Future, Deferred, Fail, Empty, stejně jako Publisher pro URLSession a Timer.
Subject je Publisher, do kterého lze ručně odesílat hodnoty. PassthroughSubject neukládá stav: odběratel dostává pouze události, které nastaly po přihlášení. CurrentValueSubject, podobný BehaviorRelay v RxSwift, ukládá aktuální hodnotu a okamžitě ji předává novému odběrateli.
Mechanismus backpressure v Combine reguluje rychlost přenosu dat. Subscriber informuje Publisher prostřednictvím subscription.request(.unlimited) nebo subscription.request(.max(N)), kolik hodnot je připraven zpracovat. To zabraňuje přetečení vyrovnávací paměti při nestejné rychlosti výrobce a spotřebitele.
Combine obsahuje více než 100 operátorů rozdělených do kategorií: transformace (map, tryMap, flatMap), filtrování (filter, compactMap, removeDuplicates), kombinování (combineLatest, merge, zip), správa času (debounce, throttle, delay) a zpracování chyb (catch, replaceError, retry).
Operátor combineLatest kombinuje poslední hodnoty dvou Publisher — pokaždé, když některý z nich emituje novou hodnotu, je uzávěr zavolán s oběma aktualizovanými hodnotami. Tento operátor je nepostradatelný při validaci formulářů, kde je třeba současně sledovat stav více vstupních polí.
Operátor debounce zpožďuje publikování hodnot, dokud neuplyne stanovený interval bez nových událostí. To je kritické pro vyhledávací pole: požadavek na server je odeslán až poté, co uživatel přestane psát na 300-500 ms, což snižuje zátěž 5-10krát.
Combine nabízí několik strategií zpracování chyb na úrovni operátorů. catch zachycuje Failure a nahrazuje Publisher záložním — tok pokračuje bez pádu. replaceError(with:) vloží výchozí hodnotu místo chyby. retry(_:) opakuje přihlášení stanovený počet opakování při selhání. Důležité: typ chyby Never v signatuře Publisher zaručuje, že tok nikdy neskončí chybou — to umožňuje použití Publisher ve SwiftUI bez zpracování Failure.
První příklad ukazuje základní práci s Just — Publisher, který emituje jednu hodnotu a končí:
let publisher = Just("Hello Combine")
publisher
.sink(receiveCompletion: { completion in
print("Dokončeno: \(completion)")
}, receiveValue: { value in
print("Přijato: \(value)")
})
Druhý příklad demonstruje integraci Combine s URLSession pro síťový požadavek se zpracováním výsledku na hlavním vlákně:
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("Chyba: \(error)")
}
}, receiveValue: { data in
print("Data přijata: \(data.count)")
})
Třetí příklad — použití CurrentValueSubject pro správu stavu:
let counter = CurrentValueSubject<Int, Never>(0)
counter
.sink { value in
print("Počítadlo: \(value)")
}
counter.send(1) // Zobrazí: Počítadlo: 1
counter.send(2) // Zobrazí: Počítadlo: 2
print(counter.value) // Zobrazí: 2
Combine a RxSwift řeší stejný úkol — reaktivní programování, ale s odlišnými přístupy. Combine je nativní framework Apple zabudovaný do systému: nevyžaduje instalaci závislostí, je integrován s SwiftUI a Foundation. RxSwift je knihovna třetí strany s podporou iOS 9+ a širší sadou operátorů.
Výkon Combine je v typických scénářích vyšší díky nativní implementaci v C. RxSwift poskytuje více nástrojů pro ladění (RxSwift.Resources.total, Debug), ale jeho objektově orientovaná architektura může být méně efektivní na velkých datových tocích. Volba mezi nimi je kompromisem mezi možnostmi a integrací.
Důležitý rozdíl — model backpressure. V Combine Subscriber spravuje demand prostřednictvím Subscription, což poskytuje explicitní kontrolu nad rychlostí toku. V RxSwift není backpressure standardně řízen — Observable emituje všechny hodnoty a Subscriber je zpracovává, jak přicházejí. Pro velké datové toky je Combine předvídatelnější a bezpečnější z hlediska paměti.
Combine je hluboce integrován s SwiftUI na úrovni jazyka. @Published generuje Publisher, ObservableObject poskytuje objectWillChange Publisher. SwiftUI View se automaticky přihlašuje k těmto Publisher a překresluje se při změnách. Pro UIKit existují externí obaly jako CombineCocoa, ale Combine byl původně navržen pro SwiftUI, takže jeho integrace v UIKit vyžaduje další kód. RxSwift má naproti tomu bohatý ekosystém pro UIKit: RxCocoa poskytuje reaktivní obaly pro všechny UI prvky.
Combine podporuje integraci s Core Data prostřednictvím NSFetchedResultsController Publisher. Publisher emituje nová data při každé změně zásobníku Core Data: přidání, odstranění, aktualizace záznamů. To umožňuje vytvářet reaktivní seznamy bez ručního volání reloadData. Kombinací Combine s NotificationCenter Publisher pro UIApplication.willResignActiveNotification vytváří vývojář reaktivní vrstvu pro celý životní cyklus aplikace bez delegátů a callback. Pro třídy ObservableObject SwiftUI automaticky aktualizuje View při změně vlastností @Published — Combine zajišťuje celé spojení bez jediného řádku ručního kódu. Modulární testování kódu Combine se provádí pomocí XCTestExpectation a Publisher.sink v testovacích případech s izolací Scheduler prostřednictvím ImmediateScheduler.
Při práci s Combine v projektech UIKit vývojáři často používají přihlášení prostřednictvím sink a ukládají AnyCancellable do Set. Typický vzor: ViewController vytvoří zobrazení, ukládá cancellables, přihlásí se k Publisher z ViewModel. Při deinit jsou všechna přihlášení automaticky zrušena prostřednictvím kolekce Cancellables. Pro správnou práci s UIControl v Combine lze použít UIControl.Event Publisher prostřednictvím rozšíření publisher(for:).
Ladění Combine se provádí pomocí operátoru print() nebo handleEvents(). print(String) loguje všechny události: receive subscription, request demand, receive value, receive completion. handleEvents poskytuje jemnější kontrolu: lze určit uzávěry pro každou fázi životního cyklu Publisher. Pro testování Combine existuje CombineExpectations — knihovna, která umožňuje kontrolovat, že Publisher emituje očekávané hodnoty v testech s virtuálním časem a kontrolou demand.
Combine se aktivně používá ve SwiftUI pro správu formulářů: každá vlastnost @Published generuje Publisher, SwiftUI se k němu přihlašuje prostřednictvím View.body. Kombinováním více Publisher prostřednictvím combineLatest se validace formuláře stává deklarativní: každý Publisher sleduje jedno pole, combineLatest shromažďuje všechny hodnoty, map je kontroluje a vrací stav tlačítka Submit. Publishers.Merge spojuje několik Publisher stejného typu do jednoho — užitečné pro shromažďování událostí z různých ovládacích prvků do jednoho toku.
Pro integraci Combine s UIKit použijte UIControl Publisher prostřednictvím rozšíření: button.publisher(for: .touchUpInside) vrací Publisher, který emituje událost při stisknutí. CombineCocoa — komunitní knihovna poskytující Publisher pro všechny události UIControl, UITextView.text, UIScrollView.contentOffset. Při zrušení přihlášení se cancellables Store čistí v deinit, což zaručuje, že žádné přihlášení nepřežije svého vlastníka. Pro UIControl s více stavy použijte Publishers.MergeMany ke sloučení Publisher do pole.
Často kladené otázky
Combine je dostupný od iOS 13, macOS 10.15, tvOS 13 a watchOS 6. To omezuje jeho použití v projektech vyžadujících podporu starších verzí. Pro iOS 12 a nižší se používá RxSwift nebo knihovny třetích stran.
PassthroughSubject neukládá stav a neopakuje poslední hodnotu novým odběratelům — ti dostávají pouze budoucí události. CurrentValueSubject ukládá aktuální hodnotu a okamžitě ji předává novému odběrateli. CurrentValueSubject.value umožňuje číst a zapisovat aktuální hodnotu synchronně.
Combine je základem SwiftUI: @Published generuje Publisher, ObservableObject používá objectWillChange Publisher. SwiftUI View se automaticky přihlašuje k @ObservedObject a @StateObject prostřednictvím pipeline Combine a překresluje View při změně vlastností.
Backpressure — mechanismus řízení rychlosti přenosu dat. Subscriber informuje Subscription, kolik hodnot je připraven zpracovat (demand). Publisher nemůže emitovat více, než bylo požadováno. To je kritické při práci s velkými datovými toky ze síťových socketů.
Operátor catch zachytí chybu a nahradí Publisher fallbackem. replaceError nahradí chybu výchozí hodnotou. retry opakuje přihlášení stanovený počet opakování při chybě. Všechny operátory by měly být umístěny před subscribe, aby se zabránilo pádu při Failure.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také