Swift Protocols in Depth

Choose a study mode

Play Quiz
Study Flashcards
Spaced Repetition
Chat to Lesson

Podcast

Play an AI-generated podcast conversation about this lesson
Download our mobile app to listen on the go
Get App

Questions and Answers

Which of the following is NOT a characteristic of a Swift protocol?

  • Specifies requirements for conforming types to implement.
  • Provides concrete implementations for all its requirements. (correct)
  • Can be adopted by classes, structures, and enumerations.
  • Defines a blueprint of methods and properties.

A protocol requiring a gettable and settable property can be satisfied by a constant stored property.

False (B)

In a protocol definition, what keyword is used to prefix type property requirements?

static

A method marked with the keyword ______ in a protocol definition indicates that conforming value types are allowed to modify their instances.

<p>mutating</p> Signup and view all the answers

Match the protocol feature with its purpose:

<p>Property Requirement = Specifies a property that conforming types must implement. Method Requirement = Specifies a method that conforming types must implement. Initializer Requirement = Specifies an initializer that conforming types must implement. Protocol Extension = Provides default implementations for protocol requirements.</p> Signup and view all the answers

Which keyword is used when implementing a protocol initializer requirement in a class?

<p>required (A)</p> Signup and view all the answers

A nonfailable initializer requirement in a protocol can only be satisfied by a nonfailable initializer in a conforming type.

<p>False (B)</p> Signup and view all the answers

What is the term for a design pattern where a class or structure hands off responsibilities to an instance of another type, facilitated by a protocol?

<p>delegation</p> Signup and view all the answers

To prevent strong reference cycles, delegates are often declared as ______ references.

<p>weak</p> Signup and view all the answers

Match the type of protocol with its application.

<p>Class-Only Protocol = Can only be adopted by class types. Protocol Composition = Combines multiple protocols into a single requirement. Optional Protocol Requirement = Does not have to be implemented by conforming types. Protocol Extension = Adds method, initializer, or property implementations to conforming types.</p> Signup and view all the answers

What operator is used to check if an instance conforms to a protocol at runtime?

<p>is (A)</p> Signup and view all the answers

When using an optional protocol requirement, the type of a method (Int) -> String automatically becomes (Int?) -> String?

<p>False (B)</p> Signup and view all the answers

What attribute must both a protocol and its optional requirements be marked with to enable optional requirements?

<p>@objc</p> Signup and view all the answers

When a protocol extension provides a default implementation for a protocol requirement, and a conforming type provides its own implementation, the ______ implementation is used.

<p>conforming type's</p> Signup and view all the answers

Associate each operator with its function in protocol conformance:

<p><code>is</code> = Checks for protocol conformance at runtime. <code>as?</code> = Attempts to downcast to a protocol type, returning an optional value. <code>as!</code> = Forces a downcast to a protocol type, potentially causing a runtime error.</p> Signup and view all the answers

What is the primary benefit of using protocol extensions in Swift?

<p>Providing default implementations for protocol requirements. (D)</p> Signup and view all the answers

Adding constraints to protocol extensions allows you to provide specialized implementations for conforming types that meet specific criteria.

<p>True (A)</p> Signup and view all the answers

What is the syntax for creating a protocol composition that requires a type to conform to both ProtocolA and ProtocolB?

<p>ProtocolA &amp; ProtocolB</p> Signup and view all the answers

A generic type can ______ conform to a protocol by listing constraints in an extension using a generic where clause.

<p>conditionally</p> Signup and view all the answers

Match the concept with its description regarding synthesized protocol implementations.

<p>Equatable = Swift can synthesize conformance for structures and enumerations with Equatable stored or associated properties. Hashable = Swift can synthesize conformance for structures and enumerations with Hashable stored or associated properties. Comparable = Swift can synthesize conformance for enumerations without raw values and with Comparable associated types.</p> Signup and view all the answers

What is the effect of declaring protocol adoption with an empty extension?

<p>It signals that the type already conforms to the protocol. (C)</p> Signup and view all the answers

If a subclass overrides a designated initalizer from a superclass, it does not need to use the override keyword when implementing a matching initializer requirement from a protocol.

<p>False (B)</p> Signup and view all the answers

What is a 'boxed protocol type'?

<p>Works with any type, chosen at runtime, that conforms to the protocol</p> Signup and view all the answers

Delegation can be used to respond to a particular ______, or to retrieve data from an external source without needing to know the underlying type of that source.

<p>action</p> Signup and view all the answers

Match the concept with the output regarding SnakesAndLadders example

<p>square &gt; 0 = â–² represents a ladder square &lt; 0 = â–¼ represents a snake Otherwise = â—‹ Represents a free square</p> Signup and view all the answers

You can limit protocol adoption to class types (and not structures or enumerations) by adding the _______ protocol to a protocol’s inheritance list.

<p>AnyObject (B)</p> Signup and view all the answers

Protocol Composition defines a new protocol type.

<p>False (B)</p> Signup and view all the answers

The objects array can now be iterated, and each object in the array can be checked to see if it conforms to the HasArea protocol. What is the downside of this?

<p>The underlying objects aren’t changed by the casting process.</p> Signup and view all the answers

Optional requirements are ________ by the optional modifier as part of the protocol’s definition.

<p>prefixed</p> Signup and view all the answers

Match the description for the Counter explanation in the text.

<p>dataSource = the data source may be nil increment(forCount:) = there's no guarantee that it implements increment(forCount:), because it’s an optional requirement.</p> Signup and view all the answers

What will print to console?

<p><code>Here's a random number: 0.3746499199817101 And here's a random Boolean: true</code> (D)</p> Signup and view all the answers

Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol.

<p>True (A)</p> Signup and view all the answers

If a conforming type provides its own implementation of a required method or property over the extension, which implementation will be used?

<p>conforming type's implementation</p> Signup and view all the answers

By constraining a collection’s elements to the Equatable protocol, a part of the Swift standard library, you can use the == and != ______ to check for equality and inequality between two elements.

<p>operators</p> Signup and view all the answers

Match the following to be accurate.

<p>equalNumbers.allEqual() = true differentNumbers.allEqual() = false</p> Signup and view all the answers

You can extend an existing type to adopt and conform to a new protocol, even if you don’t have access to the _____ code for the existing type.

<p>source (D)</p> Signup and view all the answers

The protocol name is provided after the type name, separated by a semicolon.

<p>False (B)</p> Signup and view all the answers

A generic type may be able to satisfy the requirements of a protocol only under certain conditions, such as when the type’s generic parameter conforms to the ___________.

<p>protocol</p> Signup and view all the answers

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

<p>Comparable</p> Signup and view all the answers

Match the following:

<p>Structures = stored properties that conform to the Equatable protocol Enumerations = no associated types</p> Signup and view all the answers

Flashcards

What is a protocol?

A blueprint of methods, properties, and requirements for a task.

What does it mean to adopt a protocol?

The act of a class, struct, or enum adopting a protocol.

What does it mean to conform to a protocol?

Satisfying all requirements of a protocol.

How are protocols defined?

Protocols are defined similarly to classes, structs and enums using the protocol keyword.

Signup and view all the flashcards

How do custom types adopt protocols?

List protocol names after the type's name, separated by a colon.

Signup and view all the flashcards

How does a class adopt protocols with a superclass?

List the superclass name before any protocols, followed by a comma.

Signup and view all the flashcards

What are property requirements in protocols?

Protocols can require properties with a name and type, specifying if they must be gettable or gettable and settable.

Signup and view all the flashcards

How are property requirements declared?

Always declared as variable properties, prefixed with the var keyword.

Signup and view all the flashcards

How are type property requirements defined in protocols?

Prefix type property requirements with the static keyword.

Signup and view all the flashcards

What are method requirements in protocols?

Protocols can require specific instance and type methods, without bodies.

Signup and view all the flashcards

Type method requirements

When defining type method requirements in a protocol, make sure to prefix with the keyword 'static'.

Signup and view all the flashcards

How are type method requirements defined in protocols?

Prefix type method requirements with the static keyword.

Signup and view all the flashcards

How to define mutating method requirements?

Mark the method with the mutating keyword.

Signup and view all the flashcards

Initializer Requirements

Protocols can require specific initializers to be implemented by conforming types, without bodies.

Signup and view all the flashcards

How to implement a protocol initializer requirement in a class?

Mark the initializer implementation with the required modifier.

Signup and view all the flashcards

How do subclasses implement a protocol initializer requirement?

Mark with both required and override modifiers.

Signup and view all the flashcards

What type of initializer can satisfy a failable initializer requirement?

Failable or Nonfailable

Signup and view all the flashcards

Protocols as Types

Protocols can be used as a type, enabling polymorphism. They don't implement functionality themselves.

Signup and view all the flashcards

What is Delegation?

A design pattern where an object hands off responsibilities to another type.

Signup and view all the flashcards

Why are delegates declared as weak references?

To prevent strong reference cycles.

Signup and view all the flashcards

What is the first step to implementing delegation?

Define a protocol that encapsulates the delegated responsibilities.

Signup and view all the flashcards

Adding Protocol Conformance with an Extension

You can extend an existing type to adopt and conform to a new protocol.

Signup and view all the flashcards

How to conditionally conform to a protocol?

List constraints when extending the type using a generic where clause.

Signup and view all the flashcards

How do you declare protocol adoption if a type already conforms?

Use an empty extension

Signup and view all the flashcards

Which protocols can Swift automatically provide conformance for?

Equatable, Hashable, and Comparable

Signup and view all the flashcards

For what types does Swift synthesize Equatable?

Structures/Enums with Equatable stored/associated types, or enums without associated types.

Signup and view all the flashcards

For what types does Swift synthesize Hashable?

Structures/Enums with Hashable stored/associated types, or enums without associated types.

Signup and view all the flashcards

For what types does Swift synthesize Comparable?

Enumerations without raw values (associated types must conform to Comparable).

Signup and view all the flashcards

How do you define a class-only protocol?

By adding the AnyObject protocol to a protocol’s inheritance list.

Signup and view all the flashcards

What is Protocol Composition?

Combine multiple protocols into a single requirement SomeProtocol & AnotherProtocol.

Signup and view all the flashcards

How do you check for protocol conformance?

Use the is and as operators

Signup and view all the flashcards

How to define Optional Protocol Requirements?

Prefix with the optional modifier and mark with the @objc attribute.

Signup and view all the flashcards

What is the benefit of Protocol Extensions?

All conforming types automatically gain the method implementation.

Signup and view all the flashcards

What can you provide using protocol extensions?

A default implementation to any method or computed property requirement of that protocol

Signup and view all the flashcards

How to add Constraints to Protocol Extensions?

Specify the constraints using a generic where clause.

Signup and view all the flashcards

Study Notes

  • A protocol defines a blueprint of methods, properties, and requirements.
  • Classes, structures, or enumerations can adopt protocols to provide implementations.
  • A type conforms to a protocol if it satisfies all of the protocol's requirements.
  • Protocols can be extended to implement requirements or add functionality.

Protocol Syntax

  • Protocols are defined similarly to classes, structures, and enumerations.
protocol SomeProtocol {
    // protocol definition goes here
}
  • Types adopt protocols by listing protocol names after the type name, separated by a colon.
struct SomeStructure: FirstProtocol, AnotherProtocol {
    // structure definition goes here
}
  • If a class has a superclass, list the superclass before any protocols.
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
    // class definition goes here
}

Property Requirements

  • Protocols can require conforming types to provide properties with specific names and types.
  • Protocols do not specify stored or computed properties, only the name and type.
  • Protocols specify if properties must be gettable or gettable and settable.
  • A gettable and settable property cannot be fulfilled by a constant stored property or a read-only computed property.
  • Gettable properties can be satisfied by any kind of property, even if also settable.
  • Property requirements are declared with the var keyword.
  • Gettable and settable properties are indicated by { get set } and gettable properties by { get }.
protocol SomeProtocol {
    var mustBeSettable: Int { get set }
    var doesNotNeedToBeSettable: Int { get }
}
  • Type property requirements must be prefixed with the static keyword in the protocol.
protocol AnotherProtocol {
    static var someTypeProperty: Int { get set }
}
  • FullyNamed protocol example.
protocol FullyNamed {
    var fullName: String { get }
}
  • Requires a conforming type to have a gettable instance property called fullName of type String.
struct Person: FullyNamed {
    var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName is "John Appleseed"
  • Person structure adopts and conforms to the FullyNamed protocol.
class Starship: FullyNamed {
    var prefix: String?
    var name: String
    init(name: String, prefix: String? = nil) {
        self.name = name
        self.prefix = prefix
    }
    var fullName: String {
        return (prefix != nil ? prefix! + " " : "") + name
    }
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName is "USS Enterprise"
  • Starship class adopts and conforms to the FullyNamed protocol, implementing fullName as a computed property.

Method Requirements

  • Protocols can require specific instance methods and type methods to be implemented.
  • Methods are defined without curly braces or a body in the protocol.
  • Variadic parameters are allowed, but default values are not.
  • Type method requirements are prefixed with the static keyword in the protocol.
protocol SomeProtocol {
    static func someTypeMethod()
}
  • RandomNumberGenerator protocol example.
protocol RandomNumberGenerator {
    func random() -> Double
}
  • Requires a conforming type to have an instance method called random that returns a Double value.
class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
        return lastRandom / m
    }
}
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
// Prints "Here's a random number: 0.3746499199817101"
print("And another one: \(generator.random())")
// Prints "And another one: 0.729023776863283"
  • LinearCongruentialGenerator class adopts and conforms to RandomNumberGenerator.

Mutating Method Requirements

  • Methods that modify the instance they belong to are marked with the mutating keyword.
  • Include the mutating keyword in the protocol to allow structures and enumerations to conform.
protocol Togglable {
    mutating func toggle()
}
  • Togglable protocol definition example.
enum OnOffSwitch: Togglable {
    case off, on
    mutating func toggle() {
        switch self {
        case.off:
            self =.on
        case.on:
            self =.off
        }
    }
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()
// lightSwitch is now equal to.on
  • OnOffSwitch enumeration adopts and conforms to Togglable, implementing a mutating toggle method.

Initializer Requirements

  • Protocols can require specific initializers to be implemented.
  • Defined like normal initializers but without curly braces or a body.
protocol SomeProtocol {
    init(someParameter: Int)
}

Class Implementations of Protocol Initializer Requirements

  • Initializer implementation must be marked with the required modifier.
class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // initializer implementation goes here
    }
}
  • The required modifier ensures subclasses also conform to the protocol.
  • If a subclass overrides a designated initializer and implements a protocol initializer, use both required and override modifiers.
protocol SomeProtocol {
    init()
}

class SomeSuperClass {
    init() {
        // initializer implementation goes here
    }
}

class SomeSubClass: SomeSuperClass, SomeProtocol {
    // "required" from SomeProtocol conformance; "override" from SomeSuperClass
    required override init() {
        // initializer implementation goes here
    }
}

Failable Initializer Requirements

  • Protocols can define failable initializer requirements.
  • A failable initializer requirement can be satisfied by a failable or nonfailable initializer.
  • A nonfailable initializer requirement can be satisfied by a nonfailable initializer or an implicitly unwrapped failable initializer.

Protocols as Types

  • Protocols can be used as types in code.
  • Protocols are commonly used as generic constraints.
  • Protocols can be used as opaque types, hiding the underlying type's identity.
  • Protocols can be used as boxed protocol types, which allows for runtime flexibility.

Delegation

  • Delegation is a design pattern where an object hands off responsibilities to another type.
  • This is implemented using a protocol that encapsulates the delegated responsibilities.
class DiceGame {
    let sides: Int
    let generator = LinearCongruentialGenerator()
    weak var delegate: Delegate?

    init(sides: Int) {
        self.sides = sides
    }

    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1
    }

    func play(rounds: Int) {
        delegate?.gameDidStart(self)
        for round in 1...rounds {
            let player1 = roll()
            let player2 = roll()
            if player1 == player2 {
                delegate?.game(self, didEndRound: round, winner: nil)
            } else if player1 > player2 {
                delegate?.game(self, didEndRound: round, winner: 1)
            } else {
                delegate?.game(self, didEndRound: round, winner: 2)
            }
        }
        delegate?.gameDidEnd(self)
    }

    protocol Delegate: AnyObject {
        func gameDidStart(_ game: DiceGame)
        func game(_ game: DiceGame, didEndRound round: Int, winner: Int?)
        func gameDidEnd(_ game: DiceGame)
    }
}
  • DiceGame class and DiceGame.Delegate protocol example to track game progress.
  • Delegates are declared as weak references to prevent strong reference cycles.
class DiceGameTracker: DiceGame.Delegate {
    var playerScore1 = 0
    var playerScore2 = 0
    func gameDidStart(_ game: DiceGame) {
        print("Started a new game")
        playerScore1 = 0
        playerScore2 = 0
    }
    func game(_ game: DiceGame, didEndRound round: Int, winner: Int?) {
        switch winner {
            case 1:
                playerScore1 += 1
                print("Player 1 won round \(round)")
            case 2: playerScore2 += 1
                print("Player 2 won round \(round)")
            default:
                print("The round was a draw")
        }
    }
    func gameDidEnd(_ game: DiceGame) {
        if playerScore1 == playerScore2 {
            print("The game ended in a draw.")
        } else if playerScore1 > playerScore2 {
            print("Player 1 won!")
        } else {
            print("Player 2 won!")
        }
    }
}
  • DiceGameTracker class adopts DiceGame.Delegate to track and report game events.

Adding Protocol Conformance with an Extension

  • Extensions allow existing types to adopt and conform to new protocols.
protocol TextRepresentable {
    var textualDescription: String { get }
}
  • TextRepresentable protocol example.
extension Dice: TextRepresentable {
    var textualDescription: String {
        return "A \(sides)-sided dice"
    }
}
  • Dice class extended to adopt TextRepresentable.

Conditionally Conforming to a Protocol

  • Generic types can conditionally conform to a protocol when specific conditions are met.
extension Array: TextRepresentable where Element: TextRepresentable {
    var textualDescription: String {
        let itemsAsText = self.map { $0.textualDescription }
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}
let myDice = [d6, d12]
print(myDice.textualDescription)
// Prints "[A 6-sided dice, A 12-sided dice]"
  • The Array type conforms to TextRepresentable only when its elements also conform to TextRepresentable.

Declaring Protocol Adoption with an Extension

  • Types that already meet protocol requirements can adopt the protocol with an empty extension.
struct Hamster {
    var name: String
    var textualDescription: String {
        return "A hamster named \(name)"
    }
}
extension Hamster: TextRepresentable {}
  • Hamster structure, which is then extended to conform to TextRepresentable.

Adopting a Protocol Using a Synthesized Implementation

  • Swift can automatically provide protocol conformance for Equatable, Hashable, and Comparable.
  • For Equatable, structures with Equatable stored properties and enumerations with or without Equatable associated types receive synthesized implementations of == and !=.
struct Vector3D: Equatable {
    var x = 0.0, y = 0.0, z = 0.0
}

let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
    print("These two vectors are also equivalent.")
}
// Prints "These two vectors are also equivalent."
  • Vector3D structure gets synthesized implementation of Equatable due to its Equatable properties.
  • Structures/enums with Hashable properties/associated types get Hashable synthesis.
  • Enums without raw values get Comparable synthesis.

Collection of Protocols

  • Types can adopt multiple protocols through inheritance.
  • Types can selectively inherit certain parameters from multiple protocols but not all.

Collection inheritance prettyTextualDescription

  • Types an adopt and inherit parameters from multiple protocols.
protocol PrettyTextRepresentable: TextRepresentable {
    var prettyTextualDescription: String { get }
}
  • inherits from text representable for more detailed description
extension SnakesAndLadders: PrettyTextRepresentable {
    var prettyTextualDescription: String {
        var output = textualDescription + ":\n"
        for square in board {
            switch square {
            case let ladder where ladder > 0:
                output += "â–² "
            case let snake where snake < 0:
                output += "â–¼ "
            default:
                output += "â—‹ "
            }
        }
        return output
    }
}
  • snakes and ladders implements the detailed textual description with symbols

Class-Only Protocols

  • can restrict protocol adoption to class types by adding the AnyObject protocol to a protocol’s inheritance list.
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}
  • makes it so only class types can use the protocol, not structs or enums

Protocol Composition

  • can require a type to conform to multiple protocols at the same time
  • done via simple ampersand
  • the type must conform to every single protocol
protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct Person: Named, Aged {
    var name: String
    var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
    print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
// Prints "Happy birthday, Malcolm, you're 21!"
  • has to conform to named and aged, but works

Checking for Protocol Conformance

  • use "is" operator to check conformance, and "as" to cast
  • "is" just returns true / false
  • "as?" returns an optional, nil if it does not conform
  • "as!" force casts, so it errors if it fails
protocol HasArea {
    var area: Double { get }
}
  • define the properties for area with a double get statement
class Circle: HasArea {
    let pi = 3.1415927
    var radius: Double
    var area: Double { return pi * radius * radius }
    init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
    var area: Double
    init(area: Double) { self.area = area }
}
  • implement has area to compute and return a double
class Animal {
    var legs: Int
    init(legs: Int) { self.legs = legs }
}
  • a class does not contain the properties or conform
let objects: [AnyObject] = [
    Circle(radius: 2.0),
    Country(area: 243_610),
    Animal(legs: 4)
]
  • create objects to apply conformance check for
for object in objects {
    if let objectWithArea = object as? HasArea {
        print("Area is \(objectWithArea.area)")
    } else {
        print("Something that doesn't have an area")
    }
}
// Area is 12.5663708
// Area is 243610.0
// Something that doesn't have an area
  • cycle through and determine properties and data associated

Optional Protocol Requirements

  • can define optional requirements for the protocols
  • do not have to be implemented by conforming types
  • optional requirements are prefaced by the optional modifier
  • both the protocol and optional requirements must be marked with the @objc attribute
  • protocols with this can only be applied to classes, not structs or enums
  • when methods or properties are used in this context, the entire function type is wrapper in an optional
  • optional chaining can be used to account for missing implementations
@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}
  • example with both an optional type, and variable that are optional to the protocol

Counter Optional Protocol Example

  • counter class and example on how to implement optional protocols in swift
class Counter {
    var count = 0
    var dataSource: CounterDataSource?
    func increment() {
        if let amount = dataSource?.increment?(forCount: count) {
            count += amount
        } else if let amount = dataSource?.fixedIncrement {
            count += amount
        }
    }
}
  • an incrementer for counter data with a null check
class ThreeSource: NSObject, CounterDataSource {
    let fixedIncrement = 3
}
  • A simple implementation with increment of 3
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
    counter.increment()
    print(counter.count)
}
// 3
// 6
// 9
// 12
  • for loop increases by 3 demonstrating functionality
class TowardsZeroSource: NSObject, CounterDataSource {
    func increment(forCount count: Int) -> Int {
        if count == 0 {
            return 0
        } else if count < 0 {
            return 1
        } else {
            return -1
        }
    }
}
  • complex data source example that counts to 0 from negative numbers

Protocol Extensions

  • extends protocols to provide methods, initializers, subscripts, and computed properties
  • defines behavior on protocols themselves, not conformance or global functions
extension RandomNumberGenerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}
  • generate random boolean from random, all conforming types automatically get method
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
// Prints "Here's a random number: 0.3746499199817101"
print("And here's a random Boolean: \(generator.randomBool())")
// Prints "And here's a random Boolean: true"
  • print tests the bool and ensures works
  • Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol

Providing Default Implementations

  • provides default implementation to any method or computed property requirement
  • if its implemented on the type itself, then extensions default implement is ignored
extension PrettyTextRepresentable  {
    var prettyTextualDescription: String {
        return textualDescription
    }
}
  • example of a type returning the standard implementation for textdescription

Adding Constraints to Protocol Extensions

  • only available on conforming types that satisfy specific contraints
  • generic Where clause must be implemented
extension Collection where Element: Equatable {
    func allEqual() -> Bool {
        for element in self {
            if element != self.first {
                return false
            }
        }
        return true
    }
}
  • example for checking elements in a given collection via a return bool
let equalNumbers = [100, 100, 100, 100, 100]
let differentNumbers = [100, 100, 200, 100, 200]
  • numbers for testing
print(equalNumbers.allEqual())
// Prints "true"
print(differentNumbers.allEqual())
// Prints "false"
  • tests that appropriately return true of false

Studying That Suits You

Use AI to generate personalized quizzes and flashcards to suit your learning preferences.

Quiz Team

More Like This

Swift Programming Basics Tutorial
25 questions
Swift UI: Ventajas y Aspectos Básicos de Xcode
10 questions
Overnight Restaurant Management
24 questions
Use Quizgecko on...
Browser
Browser