Combine är ett ramverk för reaktiv programmering från Apple, introducerat i iOS 13. Enligt Apple Documentation, 2025 tillhandahåller Combine ett enhetligt deklarativt API för bearbetning av asynkrona händelser. Publisher definierar datakällan och Subscriber prenumererar för att ta emot dem.
Huvudpunkter
Combine är ett deklarativt Swift-ramverk för att bearbeta asynkrona händelser över tid. Till skillnad från callback-baserade metoder tillåter Combine att beskriva databearbetningspipelines genom en kedja av operatorer. Ramverket är integrerat med Foundation (URLSession, Timer, NotificationCenter) och SwiftUI (ObservableObject, @Published).
Varje typ som implementerar protokollet Publisher måste definiera Output (typ av värden) och Failure (typ av fel). Publisher är inte aktiv förrän prenumeration — den börjar emittera händelser först efter att subscribe har anropats. Detta är kall semantik, karakteristisk för reaktiva strömmar, som ökar effektiviteten.
Subscriber tar emot händelser via tre metoder: receive(subscription:) — bekräftelse av prenumeration med demand-hantering; receive(_:) — mottagning av ett nytt värde; receive(completion:) — slutförande av strömmen med framgång eller fel. Demand anger antalet värden som Subscriber är redo att ta emot — detta är backpressure-mekanismen.
Apple tillhandahåller många inbyggda Publisher: Just emitterar ett värde och avslutas, Future — asynkront resultat med closure, Deferred — fördröjd skapelse av Publisher fram till prenumerationsögonblicket. URLSession.dataTaskPublisher omvandlar en nätverksförfrågan till en reaktiv ström. Timer.publish skapar en periodisk timer. NotificationCenter.default.publisher omvandlar notifikationer till Publisher. Dessa integrationer möjliggör prenumeration på händelser utan manuell brygga.
I Combine är Publisher och Subscriber sammankopplade via protokollet Subscription. Subscription är ett förbindande objekt som kontrollerar dataflödet. Utvecklaren behöver inte skapa egna Publisher-typer — Apple tillhandahåller inbyggda: Just, Future, Deferred, Fail, Empty, samt Publisher för URLSession och Timer.
Subject är en Publisher som manuellt kan skicka värden till. PassthroughSubject lagrar inte tillstånd: prenumeranten får endast händelser som inträffade efter prenumerationen. CurrentValueSubject, liknande BehaviorRelay i RxSwift, lagrar det aktuella värdet och överför det omedelbart till en ny prenumerant.
Mekanismen backpressure i Combine reglerar dataöverföringshastigheten. Subscriber informerar Publisher via subscription.request(.unlimited) eller subscription.request(.max(N)) hur många värden den är redo att bearbeta. Detta förhindrar buffertspill vid ojämn hastighet mellan producent och konsument.
Combine innehåller över 100 operatorer indelade i kategorier: transformering (map, tryMap, flatMap), filtrering (filter, compactMap, removeDuplicates), kombinering (combineLatest, merge, zip), tidshantering (debounce, throttle, delay) och felhantering (catch, replaceError, retry).
Operatoren combineLatest kombinerar de senaste värdena från två Publisher — varje gång någon av dem emitterar ett nytt värde anropas closuren med båda uppdaterade värdena. Denna operator är oumbärlig vid formulärvalidering där tillståndet för flera inmatningsfält måste övervakas samtidigt.
Operatoren debounce fördröjer publicering av värden tills ett specificerat intervall har passerat utan nya händelser. Detta är kritiskt för sökfält: begäran till servern skickas först efter att användaren har slutat skriva i 300-500 ms, vilket minskar belastningen 5-10 gånger.
Combine erbjuder flera strategier för felhantering på operatornivå. catch fångar upp Failure och ersätter Publisher med en reserv — strömmen fortsätter utan krasch. replaceError(with:) placerar ett standardvärde istället för felet. retry(_:) upprepar prenumerationen ett specificerat antal gånger vid misslyckande. Viktigt: feltypen Never i Publisher-signaturen garanterar att strömmen aldrig kommer att avslutas med fel — detta möjliggör användning av Publisher i SwiftUI utan hantering av Failure.
Det första exemplet visar grundläggande arbete med Just — Publisher som emitterar ett värde och avslutas:
let publisher = Just("Hello Combine")
publisher
.sink(receiveCompletion: { completion in
print("Slutfört: \(completion)")
}, receiveValue: { value in
print("Mottaget: \(value)")
})
Det andra exemplet demonstrerar integrationen av Combine med URLSession för en nätverksförfrågan med bearbetning av resultatet på huvudtråden:
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("Fel: \(error)")
}
}, receiveValue: { data in
print("Data mottaget: \(data.count)")
})
Det tredje exemplet — användning av CurrentValueSubject för tillståndshantering:
let counter = CurrentValueSubject<Int, Never>(0)
counter
.sink { value in
print("Räknare: \(value)")
}
counter.send(1) // Visar: Räknare: 1
counter.send(2) // Visar: Räknare: 2
print(counter.value) // Visar: 2
Combine och RxSwift löser samma uppgift — reaktiv programmering, men med olika tillvägagångssätt. Combine är ett inbyggt Apple-ramverk inbäddat i systemet: kräver ingen installation av beroenden, är integrerat med SwiftUI och Foundation. RxSwift är ett tredjepartsbibliotek med stöd för iOS 9+ och en bredare uppsättning operatorer.
Prestandan för Combine är högre i typiska scenarier tack vare inbyggd implementering i C. RxSwift erbjuder fler felsökningsverktyg (RxSwift.Resources.total, Debug), men dess objektorienterade arkitektur kan vara mindre effektiv på stora dataströmmar. Valet mellan dem är en kompromiss mellan funktioner och integration.
En viktig skillnad — backpressure-modellen. I Combine hanterar Subscriber demand via Subscription, vilket ger explicit kontroll över strömhastigheten. I RxSwift kontrolleras inte backpressure som standard — Observable emitterar alla värden och Subscriber bearbetar dem när de anländer. För stora dataströmmar är Combine mer förutsägbar och minnessäker.
Combine är djupt integrerat med SwiftUI på språknivå. @Published genererar Publisher, ObservableObject tillhandahåller objectWillChange Publisher. SwiftUI View prenumererar automatiskt på dessa Publisher och ritar om vid förändringar. För UIKit finns externa wrappers som CombineCocoa, men Combine var ursprungligen designat för SwiftUI, så dess integration i UIKit kräver extra kod. RxSwift har å andra sidan ett rikt ekosystem för UIKit: RxCocoa tillhandahåller reaktiva wrappers för alla UI-element.
Combine stöder integration med Core Data via NSFetchedResultsController Publisher. Publisher emitterar ny data vid varje ändring av Core Data-stacken: tillägg, borttagning, uppdatering av poster. Detta möjliggör byggande av reaktiva listor utan manuellt anrop av reloadData. Genom att kombinera Combine med NotificationCenter Publisher för UIApplication.willResignActiveNotification skapar utvecklaren ett reaktivt lager för hela applikationens livscykel utan delegater och callbacks. För ObservableObject-klasser uppdaterar SwiftUI automatiskt View vid ändring av @Published-egenskaper — Combine tillhandahåller hela anslutningen utan en enda rad manuell kod. Modulär testning av Combine-kod utförs via XCTestExpectation och Publisher.sink i testfall med Scheduler-isolering via ImmediateScheduler.
Vid arbete med Combine i UIKit-projekt använder utvecklare ofta prenumeration via sink och lagrar AnyCancellable i Set. Det typiska mönstret: ViewController skapar en vy, lagrar cancellables, prenumererar på Publisher från ViewModel. Vid deinit avbryts alla prenumerationer automatiskt via Cancellables-samlingen. För korrekt arbete med UIControl i Combine kan UIControl.Event Publisher användas via förlängningen publisher(for:).
Felsökning av Combine sker via operatorn print() eller handleEvents(). print(String) loggar alla händelser: receive subscription, request demand, receive value, receive completion. handleEvents ger finare kontroll: closures kan specificeras för varje fas av Publisherns livscykel. För testning av Combine finns CombineExpectations — ett bibliotek som gör det möjligt att kontrollera att Publisher emitterar förväntade värden i tester med virtuell tid och demand-kontroll.
Combine används aktivt i SwiftUI för formulärhantering: varje @Published-egenskap genererar en Publisher, SwiftUI prenumererar på den via View.body. Genom att kombinera flera Publisher via combineLatest blir formulärvalidering deklarativ: varje Publisher följer ett fält, combineLatest samlar alla värden, map kontrollerar dem och returnerar status för Submit-knappen. Publishers.Merge kombinerar flera Publisher av samma typ till en — användbart för att samla händelser från olika kontroller till en enda ström.
För integration av Combine med UIKit, använd UIControl Publisher via förlängning: button.publisher(for: .touchUpInside) returnerar en Publisher som emitterar en händelse vid tryckning. CombineCocoa — ett community-bibliotek som tillhandahåller Publisher för alla UIControl-händelser, UITextView.text, UIScrollView.contentOffset. Vid avslut av prenumeration rensas cancellables Store i deinit, vilket garanterar att ingen prenumeration överlever sin ägare. För UIControl med flera tillstånd, använd Publishers.MergeMany för att kombinera Publisher i en array.
Vanliga frågor
Combine är tillgängligt från iOS 13, macOS 10.15, tvOS 13 och watchOS 6. Detta begränsar användningen i projekt som kräver stöd för äldre versioner. För iOS 12 och lägre används RxSwift eller tredjepartsbibliotek.
PassthroughSubject lagrar inte tillstånd och upprepar inte det senaste värdet för nya prenumeranter — de får endast framtida händelser. CurrentValueSubject lagrar det aktuella värdet och överför det omedelbart till en ny prenumerant. CurrentValueSubject.value gör det möjligt att läsa och skriva det aktuella värdet synkront.
Combine ligger till grund för SwiftUI: @Published genererar Publisher, ObservableObject använder objectWillChange Publisher. SwiftUI View prenumererar automatiskt på @ObservedObject och @StateObject via Combine-pipelinen och ritar om View vid ändring av egenskaper.
Backpressure — en mekanism för att hantera dataöverföringshastighet. Subscriber informerar Subscription hur många värden den är redo att bearbeta (demand). Publisher kan inte emittera mer än vad som begärts. Detta är kritiskt vid arbete med stora dataströmmar från nätverkssocketar.
Operatoren catch fångar felet och ersätter Publisher med en fallback. replaceError ersätter felet med ett standardvärde. retry upprepar prenumerationen ett specificerat antal gånger vid fel. Alla operatorer bör placeras före subscribe för att förhindra krasch vid Failure.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också