Software Design

Swift Mediator Pattern Explained (Delegate Object Communication to a Mediator)

If you've grown an iOS app beyond the basics, you've probably encountered this moment.

4 min read
Cover image for Swift Mediator Pattern Explained (Delegate Object Communication to a Mediator)

If you’ve grown an iOS app beyond the basics, you’ve probably encountered this moment.

A screen has five or six views: when A changes, B must change too, and when B changes, C needs updating.

Before long, the views directly reference one another and become tangled like a ball of thread.

That’s exactly what the Mediator pattern helps organize.

The Swift Mediator pattern lowers coupling by making objects communicate only with a Mediator instead of referencing one another directly.

This article explains what the Mediator pattern is, when to use it, and how to implement it in Swift with example code.


What Is the Mediator Pattern?

In one sentence:

Place a Mediator between objects that need to communicate and route every conversation through it.

Think of an airport control tower.

If airplanes radioed one another saying, “You land first” and “I’ll go first,” it would cause a major accident.

So every airplane talks only to the control tower, which organizes the order.

The airplanes are the objects in our code, and the control tower is the Mediator.

The Mediator pattern addresses three core concerns:

  • Remove direct references: Object A no longer needs to know B, C, and D individually
  • Centralize communication logic: Complex interaction rules are gathered in one Mediator
  • Improve reusability: Independent objects are easy to reuse on other screens

When Should You Use the Mediator Pattern?

It isn’t ideal for every situation. I consider it when I see signals like these.

When objects know too much about one another—opening one class reveals a long chain of references to other objects.

Another signal is needing to modify several connected objects at once to change a single piece of logic.

Typical use cases include:

Situation Example
Complex screen UI Several buttons and labels react in sequence to form input
Component coordination Relaying messages among chat-room participants
Workflow control Managing view state at each payment step

Conversely, if there are only two or three objects with simple relationships, it’s better not to use it.

The Mediator can grow unnecessarily large and turn into a God Object.


How Do You Implement the Swift Mediator Pattern?

Let’s use a chat room example. Participants exchange messages through the chat room (the Mediator) instead of messaging one another directly.

First, define the protocol the Mediator must follow and the participants.

// Rules the Mediator must follow
protocol ChatMediator {
    func send(_ message: String, from user: User)
    func add(_ user: User)
}

The key point is that each participant knows only the Mediator and never directly references another participant.

class User {
    let name: String
    weak var mediator: ChatMediator?  // Prevent circular references

    init(name: String) { self.name = name }

    func send(_ text: String) {
        mediator?.send(text, from: self)  // Delegate to the Mediator
    }
    func receive(_ text: String) {
        print("\(name) Received: \(text)")
    }
}

Finally, the Mediator handles the actual delivery rules: it broadcasts the message only to everyone except the sender.

class ChatRoom: ChatMediator {
    private var users: [User] = []
    func add(_ user: User) { users.append(user); user.mediator = self }
    func send(_ message: String, from user: User) {
        users.filter { $0 !== user }
             .forEach { $0.receive("[\(user.name)] \(message)") }
    }
}

No matter how many users you add, the User class needs no changes. Only ChatRoom knows the delivery rules.

Everyone knows only ChatRoom, not one another
Everyone knows only ChatRoom, not one another
Turn on the example code and type along to see how it works
Turn on the example code and type along to see how it works

Mediator vs. Observer: What’s the Difference?

Many people find these two confusing.

Here’s the short version.

Category Mediator Observer
Direction Centralized many-to-many communication One-to-many notification (publish-subscribe)
Relationship Objects interact through the Mediator The subject notifies observers
Focus Complex mutual coordination Propagating state changes

In simple terms, an Observer one-sidedly announces, “I changed!”

A Mediator decides, “Who needs to do what in this situation?” and coordinates the objects.

In Swift, Combine and NotificationCenter are closer to the Observer family, while Mediators are usually implemented directly.


Frequently Asked Questions (Q&A)

Q. What if the Mediator becomes too large?

Because logic accumulates there, the Mediator can easily become bloated. Split it into several Mediators by feature or extract internal logic into separate helpers.

Q. Do I have to use weak?

Yes. If participants and the Mediator strongly reference each other, circular references cause memory leaks. Make one side weak, as in the example.

Q. Can I use it with SwiftUI?

Yes. A ViewModel often effectively acts as a Mediator between views. You can naturally coordinate multiple views’ state through one ViewModel.

Drawing one Mediator and organizing the relationships cleared my head
Drawing one Mediator and organizing the relationships cleared my head

If your objects are so tangled that touching the code feels scary, try adding the Mediator pattern.

A single Mediator makes each object much lighter and makes future feature additions less stressful.

I recommend applying today’s example code to a small project. Writing it yourself makes it click. 😊