Protocols in Swift: How to Declare Optional Methods (Full Breakdown)

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

Protocols in Swift: How to Declare Optional Methods (Complete Guide)

\n\n

Have you ever written a protocol in Swift and wanted to make a method optional? So that a class conforming to the protocol could not implement this method without the compiler complaining? If so — you are not alone. This question from Stack Overflow has gathered thousands of views, and today we will finally figure out how optional methods in Swift protocol work.

\n\n

But there is a nuance: Swift is a strictly typed language, and there are no "pure" optional methods in it. However, there are several elegant workarounds. We will look at each of them, with code examples, so you can choose the one suitable for your project.

\n\n

Why Doesn't Swift Like Optional Methods?

\n\n

In Objective-C, protocols could mark methods as @optional, and it worked. Swift, however, was designed with safety in mind from the start. If a protocol declares a method, then any class conforming to it must implement it. Otherwise — a compilation error. This is great because you won't forget to implement an important method, and the code becomes predictable.

\n\n

But in real life, you often need: "Implement the method if you want, otherwise use the default behavior." What to do? There are three main ways.

\n\n

Method 1: @objc and optional (classic, but with caveats)

\n\n

The oldest and simplest way is to use the @objc attribute. It brings the protocol into the Objective-C runtime world, where optional methods exist "out of the box."

\n\n
import Foundation\n\n@objc protocol DataSource {\n    @objc optional func fetchData() -> [String]\n    func mandatoryMethod()\n}\n\nclass MyViewController: UIViewController, DataSource {\n    func mandatoryMethod() {\n        print("Mandatory method implemented")\n    }\n    // fetchData() can be left unimplemented\n}\n\n// Usage:\nlet vc = MyViewController()\nvc.fetchData?() // Safe call — nothing will happen\nvc.mandatoryMethod()
\n\n

Pros: simplicity, clear syntax, works with delegates.

\n

Cons:

\n
    \n
  • The protocol can ONLY be used with classes (not structs, not enums).
  • \n
  • The entire protocol must be marked with @objc.
  • \n
  • You lose some Swift-specific features (associated types, where clauses).
  • \n
\n\n

This option is ideal if you are writing for iOS/macOS and working with UIKit (e.g., UITableView delegates). But for pure Swift code, it's better to use other approaches.

\n\n

Method 2: Protocol Extensions with Default Implementation (Recommended)

\n\n

This is the most Swift-way approach. You declare a protocol with required methods, and then in an extension, you provide a "default" implementation for the methods you want to make optional.

\n\n
protocol Configurable {\n    func configureUI()\n    func setupBindings() // we want to make this optional\n}\n\nextension Configurable {\n    func setupBindings() {\n        // Empty default implementation\n        print("Bindings not configured (using default implementation)")\n    }\n}\n\nclass MyView: Configurable {\n    func configureUI() {\n        print("UI configured")\n    }\n    // setupBindings() can be omitted — the extension implementation will be used\n}\n\nclass AdvancedView: Configurable {\n    func configureUI() {\n        print("Advanced UI")\n    }\n    func setupBindings() {\n        print("Custom bindings")\n    }\n}\n\nlet view = MyView()\nview.setupBindings() // Prints: "Bindings not configured (using default implementation)"\n\nlet advanced = AdvancedView()\nadvanced.setupBindings() // Prints: "Custom bindings"
\n\n

Why is this great?

\n
    \n
  • Works with classes, structs, and enums.
  • \n
  • Fully Swift-native, no objc.

Blogs

Book Recommendations