Видеокурсы по изучению языка программирования Swift. Подробнее

Проверка соответствия протоколу

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

Вы можете использовать операторы is и as, которые описаны в главе Приведение типов, для проверки соответствия протоколу и приведению к определенному протоколу. Приведение к протоколу проходит точно так же как и приведение к типу:

  • Оператор is возвращает значение true, если экземпляр соответствует протоколу и возвращает false, если нет.
  • Опциональная версия оператора понижающего приведения as? возвращает опциональное значение типа протокола, и это значение равно nil, если оно не соответствует протоколу.
  • Принудительная версия оператора понижающего приведения as осуществляет принудительное понижающее приведение, и если оно не завершается успешно, то выскакивает runtime ошибка.

Этот пример определяет протокол HasArea с единственным требованием свойства area типа Double (доступное свойство):

protocol HasArea {
    var area: Double { get }
}

Ниже представлены два класса Circle, Country, оба из которых соответствуют протоколу HasArea:

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 }
}

Класс Circle реализует требование свойства area в качестве вычисляемого свойства, основываясь на хранимом свойстве radius. Класс Country реализует требование area напрямую в качестве хранимого свойства. Оба класса корректно соответствуют протоколу HasArea.

Ниже приведен класс Animal, который не соответствует протоколу HasArea:

class Animal {
    var legs: Int
    init(legs: Int) { self.legs = legs }
}

Классы Circle, Country, Animal не имеют общего базового класса. Тем не менее они все являются классами, и их экземпляры могут быть использованы для инициализации массива, который хранит значения типов AnyObject:

let objects: [AnyObject] = [
    Circle(radius: 2.0),
    Country(area: 243_610),
    Animal(legs: 4)
]

Массив objects инициализирован при помощи литерала, содержащего экземпляры Circle, который имеет radius равный 2, экземпляр типа Country, который инициализирован площадью Великобритании в квадратных километрах, и экземпляром класса Animal, который инициализирован количеством ног.

Массив objects может быть перебран, и каждый элемент массива может быть проверен на соответствие протоколу HasArea:

for object in objects {
    if let objectWithArea = object as? HasArea {
        print("Площадь равна \(objectWithArea.area)")
    } else {
        print("Что-то такое, что не имеет площади")
    }
}
// Площадь равна 12.5663708
// Площадь равна 243610.0
// Что-то такое, что не имеет площади

Каждый раз, когда объект массива соответствует протоколу HasArea, возвращается опциональное значение при помощи оператора as?, которое разворачивается при помощи опциональной связки в константу objectWithArea. Константа objectWithArea является типом HasArea, таким образом, свойство area может быть доступно и выведено на экран способом вывода через сам тип.

Обратите внимание, что базовые объекты не меняются в процессе приведения типа. Они остаются Circle, Country и Animal. Однако в момент, когда они хранятся в константе objectWithArea, известно лишь то, что они являются типом HasArea, так что мы можем получить доступ только к свойству area.

 

Swift: 
4.0