Skip to main content
April 1, 2026Noble Desktop Publishing Team/5 min read

Protocols: Free iOS Development Tutorial

Master iOS Development with Protocol-Driven Architecture

Core iOS Development Concepts

Protocols

Define contracts and blueprints that classes must implement. Essential for delegation patterns and loose coupling.

Delegates

Allow objects to hand off responsibilities to other objects. Critical for communication between view controllers.

Conformance

Classes must implement all required protocol methods to conform. Ensures consistent behavior across implementations.

Topics Covered in This iOS Development Tutorial:

Defining a Protocol

Tutorial Learning Path

1

Protocol Definition

Learn how to define protocols using the protocol keyword and establish method signatures

2

Delegate Implementation

Understand how to create delegate properties and establish communication between classes

3

Protocol Conformance

Implement required methods to make classes conform to defined protocols

4

Testing Integration

Run and debug the implementation to see protocol delegation in action

Exercise Overview

A protocol is a fundamental building block of iOS development—defining a contract of required and optional methods or properties that classes can implement and adopt. Think of protocols as architectural blueprints that ensure consistent communication between objects in your application. In this exercise, you'll implement a custom protocol using our Car class, learning how protocols enable the delegate pattern that powers much of iOS development, from table views to network callbacks.

A protocol is a set of required and optional methods or properties that another class can implement, or adopt. Think of a protocol as a blueprint or contract that a class adheres to.
This fundamental concept underlies much of iOS development architecture

Protocol vs Class Implementation

FeatureProtocolClass
PurposeDefines contractProvides implementation
InstantiationCannot instantiateCan create objects
MethodsSignatures onlyFull implementation
InheritanceMultiple adoptionSingle inheritance
Recommended: Use protocols for defining contracts and enabling flexible, testable code architecture

Getting Started

  1. Launch Xcode if it isn't already open.

  2. Go to File > Open.

  3. Navigate to Desktop > Class Files > yourname-iOS App Dev 1 Class > Car Setup Done and double–click on Car.xcodeproj.

This code builds on our previous exercise, but notice we've now separated the Car and Mustang classes into distinct files—a best practice that improves code organization and maintainability as your projects scale. You'll see both files clearly listed in the Project navigator.

Project Setup Checklist

0/4
Project Structure Note

This exercise builds on previous work but uses separate files for Car and Mustang classes, demonstrating better code organization practices.

Defining a Protocol

Protocols in Swift are declared using the protocol keyword, similar to how you define classes and structs. However, protocols serve a different purpose—they establish blueprints containing properties and methods that conforming types must adopt. When a class implements all required protocol methods, it conforms to that protocol, enabling powerful design patterns like delegation.

  1. In the Project navigator, select Car.swift.

  2. Between the Engine structure and the Car class, around line 16, implement a protocol by typing the bold code:

    struct Engine {
       var type = ""
       var horsePower = 0
    }
    
    protocol CarDelegate {
    
    }
    
    class Car {

    This introduces a delegate pattern—one of iOS development's most essential design patterns. Delegation allows objects to hand off specific responsibilities to other objects, promoting loose coupling and reusable code. You'll encounter this pattern throughout iOS frameworks, from UITableViewDelegate to networking completion handlers.

  3. Now we need to define the methods that comprise our delegation contract. Protocols contain only method signatures and property declarations—they specify requirements without implementation details. Add the following methods as shown in bold:

    protocol CarDelegate {
       func starting()
       func didStart()
    }

    These methods establish a communication protocol for tracking car state changes. The naming convention follows iOS standards: starting() indicates an action about to occur, while didStart() confirms completion. This pattern enables responsive user interfaces that can react to state changes—for instance, showing a loading spinner during startup and updating the UI when the process completes.

  4. In the Project navigator, select ViewController.swift.

  5. At the top, add the bold code:

    class ViewController: UIViewController, CarDelegate {
  6. A red alert red circle error icon will appear to the right of the line you just added. Click it.

    The error message reads: Type 'ViewController' does not conform to protocol 'CarDelegate'

    This compile-time error demonstrates Swift's protocol safety. When a class declares conformance to a protocol, the compiler enforces that all required methods are implemented. This prevents runtime crashes and ensures your delegation contracts are fully satisfied—a significant advantage over Objective-C's optional protocol methods.

  7. To resolve this error and complete our protocol conformance, add the required method implementations using the bold code shown:

    //DELEGATE METHODS
    func starting() {
       print("Car is starting. Display UI for user to indicate car is starting.")
    }
    
    func didStart() {
       print("Car did start. Add UI to let user know car has started.")
    }
  8. In the Project navigator, return to Car.swift.

  9. Now that our protocol is defined, let's integrate it into our Car class. Create a delegate property with the CarDelegate type, noting the optional declaration that prevents retain cycles:

    var engine: Engine
    var delegate: CarDelegate?
    
    init(speed: Int, mpg: Float) {
  10. Within the start method, around line 36, add the bold code:

    func start() {
       self.speed = 10
       self.delegate?.starting()
       print("Vroom")
    }

    The optional chaining syntax (?.) safely calls the delegate method only if a delegate is assigned. This prevents crashes while maintaining clean separation of concerns—the Car class focuses on its core functionality while delegating UI responsibilities to the appropriate controller.

  11. In the Project navigator, select ViewController.swift.

  12. Establish the delegation relationship by adding the bold code:

    override func viewDidLoad() {
       super.viewDidLoad()
       // Do any additional setup after loading the view, typically from a nib.
       mustang.delegate = self
       mustang.start()
    }

    This assignment completes our delegation chain. The mustang instance (inheriting from Car) will now notify the ViewController of state changes through our protocol methods. This enables the view controller to update the user interface appropriately while keeping the Car class focused on business logic rather than UI concerns.

  13. Return to Car.swift.

  14. Complete the delegation cycle by adding the completion callback:

    func start() {
       self.speed = 10
       self.delegate?.starting()
       print("Vroom")
       self.delegate?.didStart()
    }
  15. Time to test our protocol implementation! At the top right, click the Show the Debug area button show hide debug area if it's not already visible.

  16. At the top left of Xcode, click Stop stop icon then click the Run button run icon.

    The simulator will launch, displaying a blank white screen. The real action is happening behind the scenes in our protocol implementation.

  17. Return to the main Xcode window and examine the Debug area. You should see the complete delegation sequence in the console output:

    The engine is revving Car is starting. Display UI for user to indicate car is starting. Vroom Car did start. Add UI to let user know car has started.

  18. Save your work and keep Xcode open—we'll build upon this protocol foundation in the next exercise.

Protocol Implementation Process

1

Declare Protocol

Use the protocol keyword between Engine struct and Car class around line 16

2

Add Method Signatures

Define starting() and didStart() methods within the CarDelegate protocol

3

Adopt Protocol

Make ViewController conform to CarDelegate by adding it to the class declaration

4

Implement Methods

Add concrete implementations of starting() and didStart() methods in ViewController

5

Create Delegate Property

Add optional CarDelegate property to Car class for communication

6

Connect Delegate

Set mustang.delegate = self in viewDidLoad to establish the connection

Common Conformance Error

When adopting a protocol, you must implement ALL required methods. Missing implementations will cause compile-time errors.

Delegation Pattern Benefits

Loose Coupling

Objects communicate without direct dependencies. Changes to one class don't require changes to others.

Reusability

Multiple classes can adopt the same protocol. Promotes code reuse and consistent interfaces.

Testability

Easy to create mock objects for testing. Protocols enable dependency injection and unit testing.

Code Execution Flow

Initialization

App Launch

viewDidLoad sets mustang.delegate = self

Execution

Start Method Called

mustang.start() triggers in viewDidLoad

Delegation

Starting Callback

delegate?.starting() calls ViewController method

Completion

Completion Callback

delegate?.didStart() notifies process completion

Key Takeaways

1Protocols define contracts that classes must implement, serving as blueprints for consistent behavior across different implementations
2Delegates enable loose coupling between objects by allowing one object to hand off responsibilities to another through protocol conformance
3Classes adopting protocols must implement ALL required methods to conform, ensuring complete contract fulfillment
4Optional delegate properties allow for flexible communication patterns where delegate relationships may not always be established
5The delegation pattern promotes code reusability, testability, and maintainability in iOS development
6Protocol method signatures define the interface without implementation, allowing different classes to provide their own specific behavior
7Proper delegation setup requires three steps: protocol definition, adoption declaration, and method implementation
8Debug area output helps verify that protocol methods are being called correctly during application execution

RELATED ARTICLES