Combine — mga pangunahing konsepto, Publisher at reaktibong programming

May-akda: IT Sectr Nai-publish: 2026-05-03 Oras ng pagbabasa: 11 min

Combine — ay isang native na reaktibong programming framework mula sa Apple, na ipinakilala sa iOS 13, macOS Catalina, tvOS 13 at watchOS 6. Nagbibigay ito ng deklaratibong Swift API para sa pagproseso ng mga asynchronous na kaganapan sa pamamagitan ng pattern ng Publisher at Subscriber, na pinapalitan ang mga delegate, closure at NotificationCenter ng isang pinag-isang chain. Ayon sa Apple, 2025, ang Combine ay pundasyon para sa SwiftUI at modernong iOS architecture, na gumagana nang malapit sa async/await at Structured Concurrency. Ang framework ay dinisenyo para sa komposisyon ng mga asynchronous na operasyon na may garantiya ng thread safety.

Mga pangunahing punto

  • Combine — native reaktibong framework ng Apple na may mga uri ng Publisher, Subscriber, Subject at mga uri ng error sa pamamagitan ng Failure
  • Publisher naglalabas ng mga kaganapan sa paglipas ng panahon: mga halaga ng Output, maaaring magtapos sa tagumpay o error na Failure
  • Subscriber tumatanggap ng mga kaganapan mula sa Publisher at maaaring humiling ng tiyak na bilang ng mga elemento sa pamamagitan ng Demand
  • Mga Operator map, flatMap, filter, combineLatest, zip, debounce nagbabago ng mga stream nang walang race condition
  • SwiftUI gumagamit ng Combine sa pamamagitan ng @Published, ObservableObject at @StateObject para sa reaktibong pag-update ng interface

Ano ang Combine?

Combine — ay isang deklaratibong reaktibong programming framework na nakapaloob sa Apple SDK. Ipinapatupad nito ang pattern ng Reactive Streams: Publisher ay gumagawa ng mga halaga, Subscriber ay kumokonsumo ng mga ito, at mga operator ay nagbabago ng stream sa pagitan nila. Nalulutas ng Combine ang problema ng mga callback at delegate sa pamamagitan ng pagbibigay ng pinag-isang modelo ng komposisyon para sa anumang asynchronous na kaganapan — mula sa mga tugon sa network hanggang sa mga pagbabago sa UI.

Bago ang pagdating ng Combine, ang mga iOS developer ay gumagamit ng mga third-party na library, pangunahin ang RxSwift. Nilikha ng Apple ang Combine bilang isang native na alternatibo na may malalim na integrasyon sa ecosystem: ang framework ay sumusuporta sa Objective-C sa pamamagitan ng @objc bridges, gumagana sa KVO (Key-Value Observing sa pamamagitan ng NSObject.keyValuePublisher) at NotificationCenter, at ito rin ang batayan para sa SwiftUI. Lahat ng UIKit component na nai-publish sa SwiftUI ay gumagamit ng Combine sa ilalim ng hood para sa pag-update ng mga view.

Ang Combine ay dinisenyo na isinasaalang-alang ang Swift Concurrency: mula sa iOS 15, ang Publisher ay maaaring gawing AsyncSequence sa pamamagitan ng .values at gamitin sa for-await-in loops. Ang reverse conversion ng async function sa Publisher ay ginagawa sa pamamagitan ng Future. Ayon sa Apple WWDC 2024, ang Combine ay nananatiling inirerekomendang framework para sa pagproseso ng streaming data sa UIKit application, sa kabila ng pagdating ng async/await para sa mga solong asynchronous na tawag.

Mga pangunahing konsepto ng Combine

Ang Combine ay nakabatay sa tatlong protocol: Publisher (naglalabas ng mga halaga ng uri ng Output, maaaring magtapos sa error ng uri ng Failure), Subscriber (tumatanggap ng mga halaga, namamahala ng Demand — bilang ng mga hinihiling na elemento), Subscription (kumakatawan sa koneksyon ng Publisher-Subscriber na may kakayahang kanselahin). Ang channel ng paghahatid ng data ay sinisimulan sa subscribe at nagtatapos sa cancel, completion o error. Demand — natatanging konsepto ng Combine: Ipinapaalam ng Subscriber sa Publisher kung gaano karaming elemento ang handa nitong iproseso, na nagpapatupad ng backpressure sa antas ng protocol.

Publisher at Subscriber: arkitektura ng reaktibong stream

Publisher — protocol na may dalawang kaugnay na uri: Output (uri ng mga inilalabas na halaga) at Failure (uri ng error na nagpapatupad ng Error). Kung ang stream ay hindi maaaring magtapos sa error, ang Failure ay tinukoy bilang Never — ginagarantiyahan nito sa Subscriber na ang onReceive ay tatawagin lamang na may Output. Kasama sa mga built-in na Publisher ang Just (iisang halaga), Sequence (array), URLSession.DataTaskPublisher (network request), NotificationCenter.Publisher at @Published property wrapper.

swift
import Combine

// Paglikha ng Publisher mula sa sequence
let publisher = [1, 2, 3, 4, 5].publisher

// Paglikha ng Subscriber na may pagproseso ng halaga
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("Nakumpleto")
    }
}

publisher.subscribe(PrintSubscriber())

Subscription at Demand

Subscription — ay isang protocol na kumakatawan sa aktibong koneksyon sa pagitan ng Publisher at Subscriber. Natatanggap ng Subscriber ang Subscription sa pamamaraang receive(subscription:) at tinatawag ang request(_:) para tukuyin ang Demand: .unlimited (lahat ng halaga), .max(N) (limitadong bilang) o .none (pause). Ang Demand ay maaaring dynamic na magbago — maaaring dagdagan o bawasan ng Subscriber ang bilang ng mga hinihiling na elemento sa proseso ng pagtanggap ng data. Tinitiyak nito ang backpressure nang walang buffering sa panig ng Publisher.

Subject at CurrentValueSubject

Subject — ay isang uri na pinagsasama ang Publisher at Subscriber. Ang Subject ay maaaring gamitin bilang Publisher (maaaring mag-subscribe dito) at sabay bilang Subscriber (maaaring magpadala ng mga halaga dito). Ang Combine ay nagbibigay ng dalawang uri ng Subject: PassthroughSubject (hindi nag-iimbak ng estado, nagpapasa lamang ng mga bagong halaga) at CurrentValueSubject (nag-iimbak ng kasalukuyang halaga at ipinapasa ito sa mga bagong subscriber). Ang Subject ay kinakailangan para sa integrasyon ng imperative code sa mga reaktibong chain ng Combine.

swift
let subject = PassthroughSubject<String, Never>()

// Subscription bilang Publisher
let cancellable = subject
    .map { $0.uppercased() }
    .sink { print($0) }

// Pagpapadala ng mga halaga bilang Subscriber
subject.send("hello")  // Nag-print ng “HELLO”
subject.send("mundo")  // Nag-print ng “WORLD”

CurrentValueSubject ay naiiba sa PassthroughSubject sa pagkakaroon ng paunang halaga at property na value: ang subscriber ay agad na tumatanggap ng kasalukuyang halaga sa pag-subscribe, pagkatapos lahat ng kasunod na update. Ang CurrentValueSubject.value ay accessible para sa pagbasa at pagsulat — ang pagbabago ng value ay awtomatikong nagpapadala ng bagong halaga sa lahat ng subscriber. Ginagawa nitong perpektong pagpili ang CurrentValueSubject para sa representasyon ng estado sa MVVM architecture: Ang ViewModel ay nag-publish ng CurrentValueSubject, ang View ay nag-subscribe na may mga pagbabago sa pamamagitan ng sink.

Parehong Subject ay nagpapahintulot sa pagtatapos ng stream sa pamamagitan ng pagtawag ng send(completion: .finished) o send(completion: .failure(error)). Pagkatapos ng pagtatapos, ang Subject ay humihinto sa pagtanggap at pagpapasa ng mga kaganapan. Para sa mga pangmatagalang stream na hindi dapat magtapos (hal. UI events), inirerekomenda ang paggamit ng PassthroughSubject na may Never Failure upang ibukod ang hindi sinasadyang pagtawag ng send(completion:).

Mga operator ng pagbabago at pagsasama

Mga Operator Combine — ay mga pamamaraan ng Publisher na nagbabalik ng bagong Publisher. Bawat operator ay lumilikha ng bagong object na nag-subscribe sa upstream Publisher at naglalabas ng mga binagong halaga downstream. Dahil ang Publisher ay isang generic na uri, pinapanatili ng mga operator ang mahigpit na pag-type: ang map ay nagbabago ng Output<A> sa Output<B>, ang tryMap ay nagdaragdag ng posibilidad ng error. Ang Combine ay naglalaman ng humigit-kumulang 100 built-in na operator.

KategoryaOperatorLayunin
Pagbabagomap / tryMap / flatMapPagbabago ng mga halaga o stream
Pagsalafilter / compactMap / removeDuplicatesPagpili o paglilinis ng mga halaga
PagsasamacombineLatest / zip / mergePagsasama ng maraming Publisher
Pamamahala ng orasdebounce / throttle / delayPagkaantala at pagpapaliit ng mga kaganapan
Pamamahala ng errorcatch / retry / replaceErrorPagbawi pagkatapos ng Failure
Pamamahala ng Demandbuffer / collectPag-grupo o buffering

flatMap sa Combine ay may mahalagang pagkakaiba sa bersyon ng RxSwift: tumatanggap ito ng closure na nagbabalik ng Publisher na may parehong uri ng Failure at binubuksan ang nested Publisher sa pangunahing stream. Ang flatMap na may maxPublishers: .max(1) ay kumikilos tulad ng switchMap — kinakansela ang dating nested Publisher sa pagdating ng bagong halaga. Ito ay kritikal para sa mga senaryo ng paghahanap: sa pagpasok ng bagong character, ang dating HTTP request ay awtomatikong kinakansela.

swift
// Debounce na paghahanap na may pagkansela ng nakaraang request
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)

Mga operator ng pagsasama — combineLatest at zip — gumagana tulad ng sa RxSwift: ang combineLatest ay naglalabas ng tuple ng huling halaga ng lahat ng Publisher kapag nagbago ang alinman sa kanila; ang zip ay pinagsasama ang mga halaga nang pares ayon sa index. Ang merge ay pinagsasama ang mga Publisher ng parehong uri sa isang stream, ang preserveOrder ay hindi garantisado. Sa Combine mayroon ding select — isang bihirang operator na pumipili ng unang natapos na Publisher mula sa marami, at share — multicast ng stream sa maraming subscriber nang walang paulit-ulit na pagpapatupad.

Mga Scheduler at pamamahala ng thread

Scheduler sa Combine — ay isang protocol na tumutukoy sa konteksto ng pagpapatupad para sa mga operator. Hindi tulad ng RxSwift na may 5+ built-in na Scheduler, ang Combine ay gumagamit ng umiiral na mekanismo ng Apple: DispatchQueue, RunLoop at OperationQueue. Bawat isa sa mga uri na ito ay tumutugma sa Scheduler protocol, na nagpapahintulot sa direktang pagpasa sa receive(on:) at subscribe(on:) nang walang karagdagang adapter.

receive(on:) ay nagpapalipat ng downstream sa tinukoy na Scheduler — katumbas ng observeOn sa RxSwift. Lahat ng operator pagkatapos ng receive(on:) ay isinasagawa sa tinukoy na Scheduler. subscribe(on:) ay nagpapalipat ng upstream — nakakaapekto sa pagpapatupad ng Publisher. Karaniwang pattern: subscribe(on: DispatchQueue.global()) para sa background work at receive(on: DispatchQueue.main) para sa UI update. Sa SwiftUI kapag gumagamit ng .onReceive, hindi kinakailangan ang built-in na binding sa main thread, ngunit para sa sink inirerekomenda ang explicit na receive(on:).main.

swift
// Background download + UI sa pangunahing thread
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 — alternatibo sa DispatchQueue.main para sa UI operations. Ang pagkakaiba ay ang RunLoop.main ay nakatali sa kasalukuyang event loop ng application, samantalang ang DispatchQueue.main ay nakatali sa global queue ng main thread. Para sa UIKit inirerekomenda ang DispatchQueue.main, para sa SwiftUI — RunLoop.main. ImmediateWhenScheduler ay nagsasagawa ng mga operasyon nang synchronously sa kasalukuyang thread — ginagamit bilang default para sa mga pagsubok at simpleng Publisher.

Combine at SwiftUI: integrasyon sa pamamagitan ng ObservableObject

ObservableObject — SwiftUI protocol para sa mga object na nag-publish ng mga pagbabago. Ang klase na nagpapatupad ng ObservableObject ay maaaring gumamit ng property wrapper @Published para sa mga property na ang mga pagbabago ay awtomatikong nagpapaalam sa SwiftUI tungkol sa pangangailangan ng pag-redraw. Sa ilalim ng hood, ang @Published ay lumilikha ng Publisher na nagpapaalam sa Publisher objectWillChange kapag nagbago ang wrappedValue. Ang SwiftUI ay nag-subscribe sa objectWillChange sa pamamagitan ng @StateObject, @ObservedObject o @EnvironmentObject.

@Published at @StateObject

@Published — ang pinakakaraniwang paraan ng pagsasama ng Combine sa SwiftUI. Kapag nagbago ang halaga ng @Published property, ina-update ng SwiftUI ang lahat ng View na gumagamit ng object na ito. @StateObject ay lumilikha ng instance ng ObservableObject at nag-subscribe sa mga pagbabago nito. Ang View na nilikha gamit ang @StateObject ay awtomatikong nagre-redraw kapag nagbago ang @Published properties. Kung ang object ay kailangang ipasa sa maraming View, ginagamit ang @ObservedObject o @EnvironmentObject.

swift
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 — type-eraser para sa Cancellable, na nag-iimbak ng cancellation token ng subscription. Ang Set<AnyCancellable> ay namamahala sa lifecycle ng mga subscription: sa deinitialization ng may-ari, lahat ng Cancellable ay awtomatikong kinakansela. Sa SwiftUI projects, ang Set<AnyCancellable> ay idineklara sa ObservableObject class, at ang mga subscription ay idinaragdag sa pamamagitan ng .store(in: &cancellables). Para sa UIKit, ginagamit ang parehong mekanismo na may imbakan sa UIViewController sa pamamagitan ng &cancellables o manual na pagtawag ng cancel().

Combine vs RxSwift

Combine at RxSwift ay lumulutas ng parehong gawain ng reaktibong programming, ngunit may mga pangunahing pagkakaiba sa arkitektura. Combine — bahagi ng Apple SDK na may backward compatibility hanggang iOS 13, RxSwift — third-party library na may suporta sa iOS 8+. Combine ay gumagamit ng mahigpit na pag-type ng error sa pamamagitan ng Failure generic, RxSwift — ang nag-iisang uri ng Error. Combine ay isinama sa SwiftUI sa antas ng platform, RxSwift ay nangangailangan ng RxCocoa para sa UI extensions.

Ang pagpili sa pagitan ng Combine at RxSwift ay nakadepende sa mga kinakailangan ng proyekto. Kung ang minimum na bersyon ng iOS >= 13 at ang proyekto ay gumagamit ng SwiftUI — ang Combine ay natural na pagpili dahil sa built-in na integrasyon at kawalan ng karagdagang dependencies. Kung ang proyekto ay sumusuporta sa iOS 11-12, naglalaman ng umiiral na RxSwift codebase o nangangailangan ng mga tiyak na operator na available lamang sa RxSwift (hal. Observable.from(path:)), — ang RxSwift ay nananatiling makatuwirang solusyon.

KatangianCombineRxSwift
Nag-developApple (nakapaloob sa SDK)ReactiveX (komunidad)
Bersyon ng iOSiOS 13+iOS 8+
Uri ng errorGeneric Failure (Never para sa UI)Error (anumang)
Integrasyon ng UI@Published + SwiftUIRxCocoa + UIKit
Mga Operator~100 built-in400+ operator
Swift ConcurrencySa pamamagitan ng .values (async sequence)Sa pamamagitan ng bridge library

Mga madalas itanong

Ano ang pagkakaiba sa pagitan ng PassthroughSubject at CurrentValueSubject?

PassthroughSubject ay hindi nag-iimbak ng estado — ang subscriber ay tumatanggap lamang ng mga kaganapang ipinadala pagkatapos ng subscription. CurrentValueSubject ay nag-iimbak ng kasalukuyang halaga at ipinapasa ito sa bawat bagong subscriber kaagad sa pag-subscribe. Ang CurrentValueSubject ay angkop para sa representasyon ng estado (hal. isLoggedIn).

Paano kanselahin ang subscription sa Combine?

Ang subscription ay nagbabalik ng AnyCancellable, na kinakansela kapag tinawag ang cancel() o sa deinitialization. Para sa group management gamitin ang Set<AnyCancellable> — lahat ng subscription ay kinakansela kapag na-clear ang set. Ito ay katumbas ng DisposeBag mula sa RxSwift.

Kailangan bang pag-aralan ang Combine pagkatapos ng async/await?

Oo, ang Combine ay nananatiling may kaugnayan para sa streaming data: UI events, debounce, combineLatest, WebSocket. Ang async/await ay maginhawa para sa mga solong request, Combine — para sa tuluy-tuloy o maramihang stream. Ang parehong framework ay komplementaryo — ang Publisher ay maaaring gawing AsyncSequence.

Paano gamitin ang Combine sa UIKit?

Ang UIKit ay walang built-in na Publisher, ngunit ang Apple ay nagbibigay ng extensions: NotificationCenter.default.publisher(for:), Timer.publish, URLSession.dataTaskPublisher. Para sa custom na UI events ginagamit ang PassthroughSubject o @IBAction na nakabalot sa Publisher sa pamamagitan ng Future o Subject.

Ano ang backpressure sa Combine?

Backpressure — mekanismo ng pagkontrol ng bilis ng stream: Ipinapaalam ng Subscriber sa Publisher sa pamamagitan ng Demand kung gaano karaming elemento ang handa nitong iproseso. Kung ang Demand = .max(1), ang Publisher ay naghihintay ng request bago magpadala ng susunod na halaga. Pinipigilan nito ang buffer overflow kapag hindi tugma ang bilis ng producer at consumer.

Buod

  • Combine — native reaktibong framework ng Apple para sa iOS 13+ na may Publisher-Subscriber pattern at mahigpit na pag-type ng error
  • Publisher at Subscriber ay bumubuo ng channel ng komunikasyon na may pamamahala ng Demand para sa backpressure
  • Subject (Passthrough at CurrentValue) ay isinasama ang imperative code sa mga reaktibong chain
  • Mga Operator map, flatMap, combineLatest, debounce, catch ay nagbibigay ng deklaratibong pagproseso ng stream
  • Mga Scheduler sa pamamagitan ng DispatchQueue at RunLoop ay namamahala ng execution thread nang hindi hinaharangan ang UI
  • SwiftUI ay gumagamit ng Combine sa pamamagitan ng @Published, ObservableObject at @StateObject para sa reaktibong View
  • RxSwift ay nananatiling alternatibo para sa mga proyektong may iOS 8+, Combine — pagpili para sa mga bagong proyekto sa iOS 13+

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din