Протоколы

Одной из особенностей языка Swift являются протоколы. По сути — это интерфейсы, определяющие список свойств и методов, которые должны быть реализованы принимающими классами, структурам или перечислениями. Для выстраивания иерархии, протоколы поддерживают наследование, в том числе множественное. Также их разрешается использовать как типы; отличительной чертой служит возможность создавать типы-композиции через protocol<Protocol1, Protocol2, ..., ProtocolN>.

import UIKit

protocol Selectable {
    var selected: Bool { get set }
    
    func select()
    func deselect()
}

protocol Colorable {
    func paint()
}

// Shape protocol inherits Selectable and Colorable protocols
protocol Shape: Selectable, Colorable {
    var type: String { get }
}

protocol Rounded {
    var radius: Double { get set }
}

// Oval inherits UIView class and adopts protocols Rounded and Shape
class Oval: UIView, Rounded, Shape {
    let type = "oval"
    var radius = 10.0
    var selected = false

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func select() {
        selected = true
    }

    func deselect() {
        selected = false
    }

    func paint() {
        backgroundColor = UIColor.redColor()
    }
}

class Squircle: UIView, Rounded, Shape {
    let type = "squircle"
    var radius = 3.0
    var selected = false

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func select() {
        selected = true
    }

    func deselect() {
        selected = false
    }

    func paint() {
        backgroundColor = UIColor.greenColor()
    }
}

// Define composition protocol type
typealias RoundedShape = protocol<Rounded, Shape>

// Array initialization as [protocol<Rounded, Shape>]() doesn't work
var roundedShapes = [RoundedShape]()

roundedShapes.append(Oval())
roundedShapes.append(Squircle())

С выходом Swift 2.0 протоколы обзавелись расширениями. Они позволяют добавлять реализацию по умолчанию методов и свойств (новых или уже существующих). Если необходимо, область действия расширений ограничивается только нужными типами, делается это конструкцией where.

import UIKit

// Make Selectable protocol adoptable only by classes (not structs, enums)
protocol Selectable: class {
    var selected: Bool { get set }

    func select()
    func deselect()
}

/*
Add default implementations of select() and deselect() protocol methods
and new toggleSelection() method only for UIView subclasses that adopt Selectable protocol
*/
extension Selectable where Self: UIView {
    func select() {
        selected = true
    }

    func deselect() {
        selected = false
    }

    func toggleSelection() {
        selected = !selected
    }
}

class Shape: UIView, Selectable {
    var selected = false
}

Встроенные протоколы тоже можно расширять.

import Foundation

extension BooleanType {
    var trueReverse: Bool {
        if self {
            return !Bool(self)
        } else {
            return Bool(self)
        }
    }
}

print(true.trueReverse)
// Output: false

print(false.trueReverse)
// Output: false

Дополнительные материалы: