Combine: wat is het, kernbegrippen en Publisher met Subscriber

Auteur: IT Sectr Gepubliceerd: 2026-03-17 Leestijd: 8 min

Combine is een framework voor reactief programmeren van Apple, geïntroduceerd in iOS 13. Volgens Apple Documentation, 2025 biedt Combine een uniforme declaratieve API voor het verwerken van asynchrone gebeurtenissen. Publisher definieert de gegevensbron en Subscriber abonneert zich om ze te ontvangen.

Belangrijkste

  • Combine — ingebouwd Apple-framework voor reactief programmeren, beschikbaar vanaf iOS 13
  • Publisher — protocol dat de bron van Output-waarden definieert met foutmogelijkheid Failure
  • Subscriber — protocol dat waarden ontvangt van Publisher met beheerde demand
  • Subject — Publisher die handmatig invoegen van gebeurtenissen mogelijk maakt (PassthroughSubject, CurrentValueSubject)
  • Operators — map, filter, combineLatest, flatMap voor transformatie en combineren van stromen

Wat is Combine?

Combine is een declaratief Swift-framework voor het verwerken van asynchrone gebeurtenissen in de tijd. In tegenstelling tot callback-gebaseerde benaderingen, maakt Combine het mogelijk om gegevensverwerkingspijplijnen te beschrijven via een keten van operatoren. Het framework is geïntegreerd met Foundation (URLSession, Timer, NotificationCenter) en SwiftUI (ObservableObject, @Published).

Protocol Publisher

Elk type dat het Publisher-protocol implementeert, moet Output (type waarden) en Failure (type fout) definiëren. Publisher is niet actief tot abonnement — het begint pas gebeurtenissen te emitteren na het aanroepen van subscribe. Dit is koude semantiek, kenmerkend voor reactieve streams, die de efficiëntie verhoogt.

Protocol Subscriber

Subscriber ontvangt gebeurtenissen via drie methoden: receive(subscription:) — bevestiging van abonnement met demand-beheer; receive(_:) — ontvangst van een nieuwe waarde; receive(completion:) — voltooiing van de stream met succes of fout. Demand specificeert het aantal waarden dat Subscriber bereid is te ontvangen — dit is het backpressure-mechanisme.

Ingebouwde Publishers

Apple biedt vele ingebouwde Publishers: Just emitteert één waarde en eindigt, Future — asynchroon resultaat met closure, Deferred — uitgestelde creatie van Publisher tot het moment van abonnement. URLSession.dataTaskPublisher zet een netwerkverzoek om in een reactieve stream. Timer.publish creëert een periodieke timer. NotificationCenter.default.publisher zet meldingen om in een Publisher. Deze integraties maken het mogelijk om op gebeurtenissen te abonneren zonder handmatige brug.

Publisher en Subscriber in Combine

In Combine zijn Publisher en Subscriber verbonden via het Subscription-protocol. Subscription is een verbindingsobject dat de gegevensstroom controleert. De ontwikkelaar hoeft geen eigen Publisher-typen te maken — Apple biedt ingebouwde: Just, Future, Deferred, Fail, Empty, evenals Publisher voor URLSession en Timer.

Subject in Combine

Subject is een Publisher waarin handmatig waarden kunnen worden verzonden. PassthroughSubject slaat geen status op: de abonnee ontvangt alleen gebeurtenissen die na het abonnement hebben plaatsgevonden. CurrentValueSubject, vergelijkbaar met BehaviorRelay in RxSwift, slaat de huidige waarde op en geeft deze onmiddellijk door aan een nieuwe abonnee.

Backpressure

Het backpressure-mechanisme in Combine regelt de snelheid van gegevensoverdracht. Subscriber informeert Publisher via subscription.request(.unlimited) of subscription.request(.max(N)) hoeveel waarden het klaar is om te verwerken. Dit voorkomt bufferoverloop bij ongelijke snelheid van producent en consument.

Combine-operatoren

Combine bevat meer dan 100 operatoren verdeeld in categorieën: transformatie (map, tryMap, flatMap), filtering (filter, compactMap, removeDuplicates), combineren (combineLatest, merge, zip), tijdbeheer (debounce, throttle, delay) en foutafhandeling (catch, replaceError, retry).

De operator combineLatest combineert de laatste waarden van twee Publishers — elke keer wanneer een van hen een nieuwe waarde emitteert, wordt de closure aangeroepen met beide bijgewerkte waarden. Deze operator is onmisbaar bij formuliervalidatie waar de status van meerdere invoervelden tegelijkertijd moet worden gevolgd.

De operator debounce vertraagt de publicatie van waarden totdat een gespecificeerd interval zonder nieuwe gebeurtenissen is verstreken. Dit is cruciaal voor zoekvelden: het verzoek naar de server wordt pas verzonden nadat de gebruiker 300-500 ms is gestopt met typen, wat de belasting 5-10 keer vermindert.

Foutafhandeling

Combine biedt verschillende strategieën voor foutafhandeling op operatorniveau. catch onderschept Failure en vervangt Publisher door een back-up — de stream gaat verder zonder crash. replaceError(with:) plaatst een standaardwaarde in plaats van de fout. retry(_:) herhaalt het abonnement een gespecificeerd aantal keren bij fout. Belangrijk: het fouttype Never in de handtekening van Publisher garandeert dat de stream nooit met een fout zal eindigen — dit maakt het mogelijk Publisher in SwiftUI te gebruiken zonder Failure-afhandeling.

Combine-codevoorbeelden

Het eerste voorbeeld toont basiswerk met Just — Publisher die één waarde emitteert en eindigt:

swift
let publisher = Just("Hello Combine")

publisher
    .sink(receiveCompletion: { completion in
        print("Voltooid: \(completion)")
    }, receiveValue: { value in
        print("Ontvangen: \(value)")
    })

Het tweede voorbeeld demonstreert de integratie van Combine met URLSession voor een netwerkverzoek met verwerking van het resultaat op de hoofdthread:

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("Fout: \(error)")
        }
    }, receiveValue: { data in
        print("Gegevens ontvangen: \(data.count)")
    })

Het derde voorbeeld — gebruik van CurrentValueSubject voor statusbeheer:

swift
let counter = CurrentValueSubject<Int, Never>(0)

counter
    .sink { value in
        print("Teller: \(value)")
    }

counter.send(1) // Toont: Teller: 1
counter.send(2) // Toont: Teller: 2
print(counter.value) // Toont: 2

Combine vs RxSwift

Combine en RxSwift lossen dezelfde taak op — reactief programmeren, maar met verschillende benaderingen. Combine is een native Apple-framework ingebouwd in het systeem: vereist geen installatie van afhankelijkheden, is geïntegreerd met SwiftUI en Foundation. RxSwift is een bibliotheek van derden met ondersteuning voor iOS 9+ en een bredere set operatoren.

De prestaties van Combine zijn hoger in typische scenario's dankzij native implementatie in C. RxSwift biedt meer tools voor debugging (RxSwift.Resources.total, Debug), maar de object-georiënteerde architectuur kan minder efficiënt zijn bij grote gegevensstromen. De keuze tussen hen is een compromis tussen mogelijkheden en integratie.

Een belangrijk verschil — het backpressure-model. In Combine beheert Subscriber demand via Subscription, wat expliciete controle over de stroomsnelheid geeft. In RxSwift wordt backpressure standaard niet gecontroleerd — Observable emitteert alle waarden en Subscriber verwerkt ze wanneer ze binnenkomen. Voor grote gegevensstromen blijkt Combine voorspelbaarder en geheugenvriendelijker.

Combine is diep geïntegreerd met SwiftUI op taalniveau. @Published genereert Publisher, ObservableObject biedt objectWillChange Publisher. SwiftUI View abonneert zich automatisch op deze Publishers en hertekent bij wijzigingen. Voor UIKit zijn er externe wrappers zoals CombineCocoa, maar Combine is oorspronkelijk ontworpen voor SwiftUI, dus de integratie in UIKit vereist extra code. RxSwift heeft daarentegen een rijke ecosysteem voor UIKit: RxCocoa biedt reactieve wrappers voor alle UI-elementen.

Combine ondersteunt integratie met Core Data via NSFetchedResultsController Publisher. Publisher emitteert nieuwe gegevens bij elke wijziging van de Core Data-stack: toevoegen, verwijderen, bijwerken van records. Dit maakt het mogelijk reactieve lijsten te bouwen zonder handmatig reloadData aan te roepen. Door Combine te combineren met NotificationCenter Publisher voor UIApplication.willResignActiveNotification creëert de ontwikkelaar een reactieve laag voor de hele levenscyclus van de applicatie zonder delegates en callbacks. Voor ObservableObject-klassen werkt SwiftUI View automatisch bij bij wijziging van @Published-eigenschappen — Combine zorgt voor de hele verbinding zonder een enkele regel handmatige code. Modulair testen van Combine-code gebeurt via XCTestExpectation en Publisher.sink in testcases met Scheduler-isolatie via ImmediateScheduler.

Bij het werken met Combine in UIKit-projecten gebruiken ontwikkelaars vaak abonnement via sink en slaan AnyCancellable op in Set. Het typische patroon: ViewController maakt een view aan, slaat cancellables op, abonneert zich op Publisher uit ViewModel. Bij deinit worden alle abonnementen automatisch geannuleerd via de Cancellables-collectie. Voor correct werken met UIControl in Combine kan UIControl.Event Publisher worden gebruikt via de publisher(for:)-extensie.

Debugging van Combine gebeurt via de operator print() of handleEvents(). print(String) logt alle gebeurtenissen: receive subscription, request demand, receive value, receive completion. handleEvents geeft fijnere controle: er kunnen closures worden gespecificeerd voor elke fase van de levenscyclus van Publisher. Voor het testen van Combine bestaat CombineExpectations — een bibliotheek die controleert of Publisher de verwachte waarden emitteert in tests met virtuele tijd en demand-controle.

Combine in de praktijk

Combine wordt actief gebruikt in SwiftUI voor formulierbeheer: elke @Published-eigenschap genereert een Publisher, SwiftUI abonneert zich erop via View.body. Door meerdere Publishers te combineren via combineLatest wordt formuliervalidatie declaratief: elke Publisher volgt één veld, combineLatest verzamelt alle waarden, map controleert ze en retourneert de status van de Submit-knop. Publishers.Merge combineert meerdere Publishers van hetzelfde type tot één — handig voor het verzamelen van gebeurtenissen van verschillende bedieningselementen in één stroom.

Voor integratie van Combine met UIKit gebruikt u UIControl Publisher via extensie: button.publisher(for: .touchUpInside) retourneert een Publisher die bij indrukken een gebeurtenis emitteert. CombineCocoa — een communitybibliotheek die Publisher biedt voor alle UIControl-gebeurtenissen, UITextView.text, UIScrollView.contentOffset. Bij opzegging van abonnement wordt cancellables Store in deinit opgeschoond, wat garandeert dat geen abonnement zijn eigenaar overleeft. Voor UIControl met meerdere statussen gebruikt u Publishers.MergeMany om Publishers in een array te combineren.

Veelgestelde vragen

Vanaf welke iOS-versie is Combine beschikbaar?

Combine is beschikbaar vanaf iOS 13, macOS 10.15, tvOS 13 en watchOS 6. Dit beperkt het gebruik in projecten die ondersteuning voor oudere versies vereisen. Voor iOS 12 en lager wordt RxSwift of bibliotheken van derden gebruikt.

Wat is het verschil tussen PassthroughSubject en CurrentValueSubject?

PassthroughSubject slaat geen status op en herhaalt de laatste waarde niet voor nieuwe abonnees — zij ontvangen alleen toekomstige gebeurtenissen. CurrentValueSubject slaat de huidige waarde op en geeft deze onmiddellijk door aan een nieuwe abonnee. CurrentValueSubject.value maakt het mogelijk de huidige waarde synchroon te lezen en te schrijven.

Hoe integreert Combine met SwiftUI?

Combine vormt de basis van SwiftUI: @Published genereert Publisher, ObservableObject gebruikt objectWillChange Publisher. SwiftUI View abonneert zich automatisch op @ObservedObject en @StateObject via de Combine-pijplijn en hertekent de View bij wijziging van eigenschappen.

Wat is backpressure in Combine?

Backpressure — een mechanisme voor het beheren van de gegevensoverdrachtsnelheid. Subscriber informeert Subscription hoeveel waarden het klaar is om te verwerken (demand). Publisher kan niet meer emitteren dan gevraagd. Dit is cruciaal bij het werken met grote gegevensstromen uit netwerksockets.

Hoe worden fouten afgehandeld in Combine?

De operator catch onderschept de fout en vervangt Publisher door een fallback. replaceError vervangt de fout door een standaardwaarde. retry herhaalt het abonnement een gespecificeerd aantal keren bij fout. Alle operatoren moeten vóór subscribe worden geplaatst om een crash bij Failure te voorkomen.

Samenvatting

  • Combine — ingebouwd Apple-framework voor reactief programmeren vanaf iOS 13
  • Publisher — protocol met Output en Failure, begint na abonnement
  • Subscriber — ontvangt waarden via receive met demand-ondersteuning
  • Subject (PassthroughSubject, CurrentValueSubject) — Publisher met handmatige gebeurtenisinvoeging
  • Operatoren map, filter, combineLatest, debounce, catch — basis van de pijplijn
  • Backpressure via demand voorkomt bufferoverloop van Subscriber
  • Kies Combine voor nieuwe projecten vanaf iOS 13, RxSwift — voor ondersteuning van oudere versies

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook