Swift Protocols

Sep 02, 2022swift

In Swift, a protocol defines a blueprint of methods or properties that can then be adopted by classes or any other types.

Synthesized Implementation

Swift can automatically provide the protocol conformance for Equatable, Hashable, and Comparable in many simple cases.

Swift provides a synthesized implementation of Equatable for:

  • Structs that have only stored properties that conform to Equatable
  • Enums that have only associated types that conform to Equatable
  • Enums that have no associated types

Swift provides a synthesized implementation of Hashable for:

  • Structs that have only stored properties that conform to the Hashable
  • Enums that have only associated types that conform to the Hashable
  • Enums that have no associated types

Swift provides a synthesized implementation of Comparable for:

  • Enums that don’t have a raw value.
  • Enums that have only associated types that conform to the Comparable

Protocol Extensions

Protocols can be extended to provide method, initializer, subscript, and computed property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.

Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol. Protocol inheritance is always specified in the protocol declaration itself.

You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol. If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension.

Optional Protocol Requirements

Optional requirements are available so that you can write code that interoperates with Objective-C. Both the protocol and the optional requirement must be marked with the @objc attribute. Note that @objc protocols can be adopted only by classes that inherit from Objective-C classes or other @objc classes.

@objc protocol CounterDataSource {
  @objc optional func increment(forCount count: Int) -> Int
  @objc optional var fixedIncrement: Int { get }
}

Associated Types

When defining a protocol, it’s sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name to a type that’s used as part of the protocol. The actual type to use for that associated type isn’t specified until the protocol is adopted. Associated types are specified with the associatedtype keyword.

protocol Container {
  associatedtype Item
  mutating func append(_ item: Item)
  var count: Int { get }
  subscript(i: Int) -> Item { get }
}

You can add type constraints to an associated type in a protocol to require that conforming types satisfy those constraints.

protocol Container {
  associatedtype Item: Equatable
  mutating func append(_ item: Item)
  var count: Int { get }
  subscript(i: Int) -> Item { get }
}

A protocol can appear as part of its own requirements.

protocol SuffixableContainer: Container {
  associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
  func suffix(_ size: Int) -> Suffix
}

You can include a generic where clause on an associated type.

protocol Container {
  associatedtype Item
  mutating func append(_ item: Item)
  var count: Int { get }
  subscript(i: Int) -> Item { get }

  associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
  func makeIterator() -> Iterator
}