Weak Protocol References in Swift Without @objc: A Complete Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

How to Make a Weak Protocol Reference in Pure Swift (Without @objc)? A Complete Guide with Examples

\n\n

Imagine: you are writing an app in Swift, using the Delegate pattern, and suddenly — bam! — your objects are not being deallocated, memory is growing, and the app starts to lag. Sound familiar? Most likely, you have encountered a retain cycle (a cycle of strong references). A classic problem where the delegate holds a strong reference to the owner, and the owner holds a strong reference to the delegate. The solution that first comes to mind is to make the protocol reference weak (weak). But here Swift throws a surprise: you cannot simply declare weak var delegate: MyProtocol if the protocol is not marked with @objc. The compiler will give an error. Why? And most importantly — how to get around this?

\n\n

In this article, we will break down how to make a weak protocol reference in pure Swift without @objc. You will learn why this is a problem in the first place, what solutions exist, and how to write clean, safe code without memory leaks. Let's go!

\n\n

Why Doesn't Weak Protocol Reference Work "Out of the Box"?

\n\n

Let's recall how weak works in Swift. A weak reference (weak) can only exist for reference types (classes). Why? Because only class objects have memory management through ARC (Automatic Reference Counting). Structures (struct) and enumerations (enum) are value types, they are copied, and the concept of a "weak reference" does not make sense for them.

\n\n

When you write:

\n
weak var delegate: MyProtocol?
\n

The compiler does not know whether MyProtocol will be implemented by a class, a structure, or an enumeration. What if it is a structure? Then weak cannot be applied. Hence the error: «'weak' may only be applied to class and class-bound protocol types».

\n\n

In the past (in Objective-C), all protocols could by default only be implemented by classes, so weak worked. In pure Swift, protocols are universal — and this is great, but it adds complexity.

\n\n

Solution #1: Class-Bound Protocol

\n\n

The simplest and most common way is to explicitly specify that the protocol can be implemented only by classes. For this, the keyword AnyObject (or the deprecated class) is used in the protocol declaration.

\n\n

Example:

\n
protocol MyDelegate: AnyObject {\n    func didSomething()\n}\n\nclass ViewController {\n    weak var delegate: MyDelegate?\n\n    func doSomething() {\n        delegate?.didSomething()\n    }\n}\n\nclass SomeClass: MyDelegate {\n    func didSomething() {\n        print("Delegate triggered!")\n    }\n}\n\n// Usage\nlet vc = ViewController()\nlet some = SomeClass()\nvc.delegate = some\nvc.doSomething() // Prints: "Delegate triggered!"
\n\n

Everything works. MyDelegate can now only be implemented by a class (class), and weak is legal. This is the Apple-recommended approach for delegates.

\n\n

Why is this good?

\n
    \n
  • Simplicity and readability.
  • \n
  • Full ARC support.
  • \n
  • No need for @objc.
  • \n
\n\n

Cons?

\n
    \n
  • You lose the ability to implement the protocol with a structure. But for delegates, this is usually not needed.
  • \n
\n\n

Solution #2: Using a Generic Wrapper (For Exotic Cases)

\n\n

What if you must allow the protocol to be implemented by both classes and structures, but still want a weak reference? This is rare, but possible. For example, you are writing a library where the user can pass both a class and a structure. Then a wrapper comes to the rescue.

\n\n

The idea: create a structure that stores a weak reference to an object implementing the protocol. For classes — we

Blogs

Book Recommendations