Combine: co to je, klíčové pojmy a Publisher s Subscriber

Autor: IT Sectr Publikováno: 2026-03-17 Doba čtení: 8 min

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 — vestavěný framework Apple pro reaktivní programování, dostupný od iOS 13
  • Publisher — protokol určující zdroj hodnot Output s možností chyby Failure
  • Subscriber — protokol přijímající hodnoty od Publisher se spravovaným demand
  • Subject — Publisher umožňující ruční vkládání událostí (PassthroughSubject, CurrentValueSubject)
  • Operators — map, filter, combineLatest, flatMap pro transformaci a kombinování toků

Co je Combine?

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).

Protokol Publisher

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.

Protokol Subscriber

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.

Vestavěné Publisher

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.

Publisher a Subscriber v Combine

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 v Combine

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.

Backpressure

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.

Operátory Combine

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.

Zpracování chyb

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.

Příklady kódu Combine

První příklad ukazuje základní práci s Just — Publisher, který emituje jednu hodnotu a končí:

swift
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ě:

swift
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:

swift
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 vs RxSwift

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 v praxi

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

Od jaké verze iOS je Combine dostupný?

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.

Čím se liší PassthroughSubject od CurrentValueSubject?

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ě.

Jak se Combine integruje se SwiftUI?

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í.

Co je backpressure v Combine?

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ů.

Jak zpracovávat chyby v Combine?

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í

  • Combine — vestavěný framework Apple pro reaktivní programování od iOS 13
  • Publisher — protokol s Output a Failure, začíná po přihlášení
  • Subscriber — přijímá hodnoty prostřednictvím receive s podporou demand
  • Subject (PassthroughSubject, CurrentValueSubject) — Publisher s ručním vkládáním událostí
  • Operátory map, filter, combineLatest, debounce, catch — základ pipeline
  • Backpressure prostřednictvím demand zabraňuje přetečení bufferu Subscriber
  • Zvolte Combine pro nové projekty od iOS 13, RxSwift — pro podporu starších verzí

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í.

Prodiskutovat projekt

Přečtěte si také