Swift: Protocols (Протоколы)

Для тех кто пришел из мира C++/C#/Java — это по другому названные интерфейсы.
Протокол определяет как должен выглядеть тип (класс, структура, перечисление), какие свойства, методы должны быть реализованы, но не определяет их сам.

Синтаксис:

Протокол может затребовать у типа его реализующего:
1) реализовать свойство экземпляра (хранимое или вычисляемое — не важно), которое можно как читать так и писать
2) реализовать свойство экземпляра только для чтения
3) реализовать свойство типа (любые комбинации get/set)
4) реализовать метод экземпляра
5) реализовать метод типа
6) определить инициализатор
7) определить failable инициализатор

Пример класса который соответствует данному протоколу

1) важно, все инициализаторы, которые имплементируют требования протокола — обязаны иметь ключевое слово required перед init. Но если класс помечен как final (его нельзя будет отнаследовать), то required можно не указывать
Если наследник переопределяет designited инициализатор из родителя и также имплементирует совпадающий инициализатор из протокола, то необходимо указывать как override так и required перед init

Для значимых типов можно затребовать mutating метод — позволяющий изменить экземпляр

Протокол — это полноценный тип, поэтому его можно использовать как:
— параметр или возвращаемое значение функций, методов или инициализаторов
— тип для переменной, константы или свойства
— тип для массива, словаря и других контейнеров

Delegation

Часто протоколы применяют для делегирования, — когда какой то объект должен поручить выполнять работу другому объекту но он о нем ничего не должен знать, для этого и существует делегирование обязанностей.
Пожалуй самым известным примером делегирования является протокол UITableViewDataSource, в котором если отбросить все опциональные методы (все помеченное в протоколе как optional — не обязательно для реализации в типе его имплементирующем), то выглядеть он будет как то так:

Т.е. класс имплементирующий UITableViewDataSource — обязан отдавать число строк в секции и ячейку по индексу. Обычно это имплементирует наш контроллер которого мы подсовываем в TableViewController как dataSource. Таким образом работа будет выполнена, хотя TableViewController ничего не будет знать о нашем контроллере, он знает лишь о протоколе. Впрочем по паттернам лучше почитать отдельно, тема слишком обширная.

Благодаря расширениям мы можем любой тип, даже базовый от Apple научить имплементировать наш протокол, что обеспечивает гибкость

Это позволит Int присваивать в массив типа протокола и работать с ним как с классом, определяя конкретный тип с помощью тех же isas

Протоколы могут наследоваться, правила идентичны наследованию других типов.
Если протокол предназначен только для классов, то необходимо это указать с помощью ключевого слова class

Если необходимо, чтобы параметр соответствовал нескольким протоколам — они тип этого параметра определяется как

Опциональность требований протокола имеет пару нюансов

1) протокол у которого есть опциональные члены обязан быть помечен ключевым словом @objc, так же как и класс его реализующий, но можно отмечать с помощью @objc и конкретные опциональные члены,

2) возвращаемое значение опциональных свойств всегда приводится к опциональному типу (int : Int? я указал специально, подчеркивая что int : Int вызывало бы ошибку, но тип можно вообще не указывать конечно)
3) при вызове опционального метода — необходимо указать знак вопроса после имени метода — перед скобками. Если вы уверены что данный тип точно реализует этот опциональный метод, можно указать ! вместо ?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *