Lesson 72Protocols
Protocol Requirements
Types of Requirements
Protocols can require different types of members. Understanding each type helps you design better protocols!
Requirement Types
Properties
Instance & static properties
var name: Type { get set }Methods
Instance & static methods
func doWork()Initializers
Required constructors
init(param: Type)Subscripts
Index access
subscript(i: Int) -> TMutating Methods
Use mutating for methods that modify value types:
mutating func toggle()
Classes don't need the mutating keyword when implementing.
Class Initializer Rules
- Use
requiredkeyword in class implementations - Failable init
init?can be satisfied byinitorinit! - Non-failable
initcan satisfyinit?requirement
Associated Types Preview
Protocols can have placeholder types using associatedtype. We'll cover this in detail in Lesson 74!
main.swift
// PROTOCOL REQUIREMENTS
// Different types of requirements protocols can define
// PROPERTY REQUIREMENTS
protocol FullyNamed {
var fullName: String { get } // Read-only requirement
}
protocol Configurable {
var isEnabled: Bool { get set } // Read-write requirement
}
struct Person: FullyNamed {
var firstName: String
var lastName: String
var fullName: String { // Computed property satisfies get
return "\(firstName) \(lastName)"
}
}
class Device: Configurable {
var isEnabled: Bool = false // Stored property satisfies get set
}
// STATIC PROPERTY REQUIREMENTS
protocol Countable {
static var count: Int { get set }
}
struct Item: Countable {
static var count: Int = 0
init() {
Item.count += 1
}
}
// METHOD REQUIREMENTS
protocol Toggleable {
mutating func toggle()
}
struct Switch: Toggleable {
var isOn: Bool = false
mutating func toggle() {
isOn = !isOn
}
}
// Note: Classes don't need 'mutating'
class Light: Toggleable {
var isOn: Bool = false
func toggle() { // No mutating keyword needed
isOn = !isOn
}
}
// STATIC METHOD REQUIREMENTS
protocol Creatable {
static func create() -> Self
}
class Document: Creatable {
required init() { }
static func create() -> Self {
return self.init()
}
}
// INITIALIZER REQUIREMENTS
protocol Initializable {
init(value: Int)
}
// Classes must use 'required' keyword
class Counter: Initializable {
var value: Int
required init(value: Int) {
self.value = value
}
}
// Structs don't need 'required'
struct Score: Initializable {
var value: Int
init(value: Int) {
self.value = value
}
}
// FAILABLE INITIALIZER REQUIREMENTS
protocol StringInitializable {
init?(from string: String)
}
struct Age: StringInitializable {
var value: Int
init?(from string: String) {
guard let age = Int(string), age >= 0 else {
return nil
}
self.value = age
}
}
// SUBSCRIPT REQUIREMENTS
protocol Indexable {
subscript(index: Int) -> String { get }
}
struct StringList: Indexable {
var items: [String]
subscript(index: Int) -> String {
return items[index]
}
}
// ASSOCIATED TYPE REQUIREMENTS (Preview)
protocol Container {
associatedtype Item
var items: [Item] { get set }
mutating func append(_ item: Item)
}
struct IntContainer: Container {
var items: [Int] = []
mutating func append(_ item: Int) {
items.append(item)
}
}Try It Yourself!
Create a Resettable protocol with a mutating reset() method and a static defaultValue property. Implement it in a Counter struct!