An Xcode Agent Prompt: What It Signals for Combine and RxSwift


Greetings, traveler!

While poking around Xcode’s agent prompts, people noticed a blunt instruction:

Avoid using the Combine framework and instead prefer to use Swift’s async and await versions of APIs instead.

That reads harsher than the older guidance many of us saw last year, which said:

In general, prefer the use of Swift Concurrency (async/await, actors, etc.) over tools like Dispatch or Combine, but if the user’s code or words show you they may prefer something else, you should be flexible to this preference.

So what is this? A quiet deprecation notice? A shift in Apple’s strategy? Or just an AI prompt doing AI prompt things?

Why reactive frameworks showed up in the first place

Before Swift had a first-class concurrency model, iOS devs lived in a world of callbacks, delegation, NotificationCenter, and hand-rolled state machines. It worked, but “works” is doing a lot of heavy lifting here. You ended up with:

  • pyramids of completion handlers
  • ad-hoc cancellation
  • threading rules hidden in comments
  • UI state that drifted away from the data source

Reactive programming promised a different shape: model your app as streams of values over time, then compose transformations. RxSwift rode that wave and became the default answer in many teams between roughly 2015 and 2019.

It was popular for good reasons:

  • you could express complex chains of async work as a pipeline
  • you could unify UI events, network events, timers, and state changes
  • you could centralize error handling and cancellation patterns
  • you could build predictable “data flows” in MVVM-style architectures

However, RxSwift’s biggest strength is also its biggest problem: it scales in expressive power faster than it scales in readability.

RxSwift is hard to learn

You can teach someone map and flatMap in a day. You cannot teach the whole mental model in a week. Even Rx advocates describe the learning curve as steep.

In a real team, that turns into a hiring constraint. You either:

  • narrow your candidate pool to people who already speak Rx
  • hire engineers and spend months ramping them up
  • accept that only a subset of the team feels safe touching core flows

RxSwift makes some bugs annoying to catch

Reactive chains tend to fail in ways that feel indirect. You see the symptom in one place and the cause lives three operators earlier.

Common pain points show up in the same places again and again:

  • memory leaks from subscription ownership and retain cycles
  • lifecycle mismatches where subscriptions outlive the screen you thought owned them
  • thread issues caused by scheduler choices and implicit hops

DisposeBag alone is a recurring source of “why didn’t this get cleaned up” questions. And retain cycles in Rx code are easy to create and easy to miss during review.

Debugging also changes shape. You spend more time inspecting timelines, schedulers, and disposal behavior than stepping through a straightforward call stack.

Architecture gets heavier than it needs to be

RxSwift often becomes a default tool, even when the problem is simple. A one-shot request turns into a publisher chain. A couple of callbacks become a graph of streams.

This is rarely done with bad intentions. Teams want consistency. They want one mental model. The trouble is that the cost shows up later, when you need to maintain it, refactor it, or explain it to someone new.

It is a third-party dependency

RxSwift is mature, widely used, and unlikely to break overnight. Still, it sits outside Apple’s compatibility contract. If Apple ships a new platform constraint, or a new language feature that changes how concurrency is expected to work, RxSwift has to adapt from the outside.

When a project is “fully threaded through Rx”, any disruption becomes systemic. You do not swap it out in a sprint.

Swiftui changed the UI layer game

SwiftUI made “reactive UI” feel native. State drives the view. Updates propagate through property wrappers. The framework already treats UI as a function of state.

It means RxSwift stopped being the obvious center of the UI layer. Many teams kept RxSwift for data flows and business logic, then bridged into SwiftUI at the edges. Others moved entirely to Combine because the integration story was cleaner.

Apple’s take: Combine

In 2019 Apple introduced Combine as its first-party reactive framework, right alongside SwiftUI.

Combine gave the ecosystem a native vocabulary:

  • Publisher / Subscriber
  • operators that mirror the reactive world
  • built-in integration points used heavily in SwiftUI patterns

It was also a strategic move: “reactive programming exists, so here is our platform version.”

Then async/await arrived

Chris Lattner’s Swift Concurrency Manifesto sketched the direction years earlier: async/await as the abstraction, with a coherent model that fits the language.

When async/await landed, it did two things at once:

  • it made a huge chunk of async code read like normal code again
  • it gave Apple a language-level story for cancellation, structured tasks, and safety

The industry already knew this pattern. Swift’s version made it feel like the default path forward.

At that point, many teams tried to migrate away from reactive pipelines. That is where reality hits: migration is rarely a mechanical “replace operator with await.” The reactive and structured-concurrency models slice problems differently.

Some reactive use cases still do not have a perfect one-liner equivalent in core concurrency. That gap is part of why Apple ships AsyncAlgorithms: a package that brings familiar “values over time” operators to AsyncSequence, including things like debounce, throttle, merge, combineLatest, and zip.

The prompts: from “prefer” to “avoid”

First, a flexible guideline in Xcode prompts:
“In general, prefer the use of Swift Concurrency (async/await, actors, etc.) over tools like Dispatch or Combine, but … be flexible…”

Then, with Xcode 26.3 and agentic coding, a sharper rule appeared:
“Avoid using the Combine framework and instead prefer to use Swift’s async and await versions of APIs instead.”

If you only read that second line, it is tempting to conclude “Combine is unwanted now.”

I think the right conclusion is narrower:

Apple wants the agent to generate code that matches the platform’s default direction.

An agent that sprays Combine across a codebase creates long-term maintenance debt in a way Apple cannot control. An agent that sticks to async/await produces code that is easier to review, easier to debug, and more consistent with modern Apple examples.

That is an engineering policy for code generation, not a deprecation note.

Combine still exists, still has official documentation, and still solves problems well.

A simple way to summarize how teams experienced the shifts:

  • 2015–2019: RxSwift dominates
  • 2019–2022: Combine as Apple’s answer
  • 2023–2026: async/await dominates

What this implies for RxSwift

A shift away from Combine as the default may be an even stronger shift away from RxSwift as an architectural standard.

If Apple’s own reactive framework is something the Xcode agent should avoid by default, a third-party reactive framework sits even further from the center of gravity.

It makes RxSwift a specialized tool:

  • still useful when your product is built around complex streams
  • still practical in mature codebases where a rewrite is not worth it
  • still valuable when you need operator vocabulary that your team already understands

However, it stops being the safest default for a brand-new project.

Where agentic coding fits into this story

Xcode 26.3 introduced agentic coding, letting coding agents act in the IDE and use Xcode’s tools more autonomously.

That matters because agents do not just write isolated functions. They propagate patterns. If the agent’s prompt says “avoid Combine,” it will prefer async/await across new code it touches. Over time, this nudges projects toward a concurrency-first baseline.

If your app is deeply Reactive-based, you can still use agentic coding. You will want to give the agent explicit constraints, otherwise it may keep trying to “modernize” things into async/await, sometimes in ways that fight your architecture.

Conclusion

Reactive frameworks are not going away tomorrow. They are also no longer the future Apple is pushing the ecosystem toward.

Swift Concurrency is the default mental model now. Apple even encodes that bias into Xcode’s agent prompts.

If you start a new project today, it is worth treating reactive frameworks as an intentional choice, not the baseline. There are still cases where streams are the cleanest tool, and AsyncAlgorithms exists partly because those patterns matter.

One more detail that keeps coming up in community discussions: Combine has had long stretches without headline-level evolution since around the Swift Concurrency rollout era, which fed speculation about its trajectory.

None of this forces a rewrite. It does suggest a new default.

If you want your codebase to match where Apple is steering the platform, async/await becomes the foundation, and reactive moves to the edges, used where it clearly pays for itself.